From 1a272bc5551321a6bbc41c0906677322035fb615 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Tue, 10 Jan 2012 09:38:51 -0800 Subject: [PATCH 01/24] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 620a3e6..01145ac 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "name": "ldapjs", "homepage": "http://ldapjs.org", "description": "LDAP client and server APIs", - "version": "0.4.3", + "version": "0.4.4", "repository": { "type": "git", "url": "git://github.com/mcavage/node-ldapjs.git" From 4730d2564e178b03a1678e46eea5b4fe0dc20e9d Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 14 Jan 2012 10:21:50 -0800 Subject: [PATCH 02/24] travis config --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6073839 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js + node_js: + - 0.4 + - 0.6 \ No newline at end of file From c908d8f0dc4eb9504a1a0bab1cbda5f415299c5d Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 14 Jan 2012 10:30:28 -0800 Subject: [PATCH 03/24] travis tweak --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6073839..f1d0f13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: node_js - node_js: - - 0.4 - - 0.6 \ No newline at end of file +node_js: + - 0.4 + - 0.6 From 1690a3f3f18ce8914917c9fb1a1c01c5b85c8d34 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 08:04:07 -0800 Subject: [PATCH 04/24] GH-48 Ensure escaped filters work --- tst/filters/parse.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tst/filters/parse.test.js diff --git a/tst/filters/parse.test.js b/tst/filters/parse.test.js new file mode 100644 index 0000000..12da35d --- /dev/null +++ b/tst/filters/parse.test.js @@ -0,0 +1,19 @@ +// Copyright 2011 Mark Cavage, Inc. All rights reserved. + +var test = require('tap').test; + +var parse = require('../../lib/index').parseFilter; + + + +test('GH-48 XML Strings in filter', function(t) { + var str = '(&(CentralUIEnrollments=\\*)(objectClass=User))'; + var 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(); +}); From d09a2ee7112a9550e5558e1d757bc5379a9a17c1 Mon Sep 17 00:00:00 2001 From: Craig Baker Date: Thu, 19 Jan 2012 15:18:20 -0500 Subject: [PATCH 05/24] changed out a stack based filter parser for a operator/operand k-ary tree based parser. --- lib/filters/index.js | 225 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 224 insertions(+), 1 deletion(-) diff --git a/lib/filters/index.js b/lib/filters/index.js index 448fd4c..f2653f6 100644 --- a/lib/filters/index.js +++ b/lib/filters/index.js @@ -96,6 +96,229 @@ function _filterStringToStack(str) { } +//expression parsing +//returns the index of the closing parenthesis matching the open paren specified by openParenIndex +function matchParens(str, openParenIndex){ + var stack = []; + + for(var i=openParenIndex || 0;i=') != -1){ + operatorStr = '>='; + tree.tag = 'greaterOrEqual'; + valueOffset = 2; + }else if(expr.indexOf('<=') != -1){ + operatorStr = '<='; + tree.tag = 'lessOrEqual'; + valueOffset = 2; + }else if(expr.indexOf("=") != -1){ + operatorStr = '='; + tree.tag = 'equalityMatch'; + valueOffset = 1; + }else { + tree.tag = 'present'; + } + console.log('operatorStr: ' + operatorStr + '; valueOffset: ' + valueOffset); + if (operatorStr == ""){ + tree.name = expr; + }else{ + //pull out lhs and rhs of equality operator + //var index = expr.indexOf('='); + + var splitAry = expr.split(operatorStr,2); + tree.name =splitAry[0]; + tree.value = splitAry[1]; + + if (tree.value.indexOf('*') != -1 && tree.tag == 'equalityMatch'){ + tree.tag = 'substrings'; + var split = tree.value.split("*"); + if(tree.value.indexOf("*") != 0){ + tree.initial = split.shift(); + }else{ + split.shift(); + } + if(tree.value.lastIndexOf("*") != tree.value.length-1){ + tree['final'] = split.pop(); + }else{ + split.pop(); + } + tree.any = split; + } + if(tree.value.length == 0){ + tree.tag = 'present'; + } + } + } + + return tree; +}; + +var treeToObjs = function(tree,filterObj){ + console.log("in treeToObjs"); + if(tree === undefined){ + return filterObj; + } + + if(tree.length === 0){ + return filterObj; + } + + var currentFilter = filterObj; + if(tree.op != "expr"){ + console.log("adding "+tree.op+" to filters"); + switch (tree.op){ + case "and": + filterObj.addFilter(currentFilter = new AndFilter({filters:[]})); + break; + case "or": + filterObj.addFilter(currentFilter = new OrFilter({filters:[]})); + break; + case "not": + filterObj.addFilter(currentFilter = new NotFilter({filters:[]})); + break; + } + for(var i = 0,tempFilter,child;i Date: Thu, 19 Jan 2012 15:25:20 -0500 Subject: [PATCH 06/24] Removed commented out code and some left over console.log's. --- lib/filters/index.js | 234 +++++++------------------------------------ 1 file changed, 37 insertions(+), 197 deletions(-) diff --git a/lib/filters/index.js b/lib/filters/index.js index f2653f6..6a7d07d 100644 --- a/lib/filters/index.js +++ b/lib/filters/index.js @@ -28,74 +28,6 @@ var BerReader = asn1.BerReader; ///--- Internal Parsers - -/* - * This is a pretty naive approach to parsing, but it's relatively short amount - * of code. Basically, we just build a stack as we go. - */ -function _filterStringToStack(str) { - assert.ok(str); - - var tmp = ''; - var esc = false; - var stack = []; - var depth = -1; - var open = false; - for (var i = 0; i < str.length; i++) { - var c = str[i]; - - if (esc) { - esc = false; - tmp += c; - continue; - } - - switch (c) { - case '(': - open = true; - tmp = ''; - stack[++depth] = ''; - break; - case ')': - if (open) { - stack[depth].value = tmp; - tmp = ''; - } - open = false; - break; - case '&': - case '|': - case '!': - stack[depth] = c; - break; - case '=': - stack[depth] = { attribute: tmp, op: c }; - tmp = ''; - break; - case '>': - case '<': - case '~': - if (!(str[++i] === '=')) - throw new Error('Invalid filter: ' + tmp + c + str[i]); - - stack[depth] = {attribute: tmp, op: c}; - tmp = ''; - break; - case '\\': - esc = true; - default: - tmp += c; - break; - } - } - - if (open) - throw new Error('Invalid filter: ' + str); - - return stack; -} - - //expression parsing //returns the index of the closing parenthesis matching the open paren specified by openParenIndex function matchParens(str, openParenIndex){ @@ -115,16 +47,17 @@ function matchParens(str, openParenIndex){ //console.log('[_findMatchingParenthesis]: returning ', str.length-1); return str.length-1; }; + + //recursive function that builds a filter tree from a string expression -//the filter tree is an intermediary step between the incoming expression and the outgoing Dsml. -//see the comments of store.fetch concerning the filter argument for more info +//the filter tree is an intermediary step between the incoming expression and the outgoing Filter Class structure. function _buildFilterTree(expr){ - console.log('[buildFilterTree]: expression: ',expr); + //console.log('[buildFilterTree]: expression: ',expr); var tree = {}; if(expr.length === 0){ return tree; } - console.log(expr); + //console.log(expr); //remove leading and trailing parenthesis if they are there if (expr.charAt(0) == '('){ @@ -132,7 +65,7 @@ function _buildFilterTree(expr){ console.log('substring: '+expr); } - //store prefix op + //store prefix operator if(expr.charAt(0) == '&'){ tree.op = 'and'; expr = expr.substring(1); @@ -166,7 +99,11 @@ function _buildFilterTree(expr){ i++; } }else{ - //else its equality expression, parse and return as such + //else its some sort of non-logical expression, parse and return as such + + //tag represents the name of the operator, initially this library was used to + //encode a filter string into DSML where the tag name would be + //so thats why its named tag, if you were wondering... var operatorStr = ""; var valueOffset=0; tree.name = ""; @@ -201,14 +138,24 @@ function _buildFilterTree(expr){ tree.name =splitAry[0]; tree.value = splitAry[1]; + //substrings fall into the equality bin in the switch above + //so we need another check here to look for * if (tree.value.indexOf('*') != -1 && tree.tag == 'equalityMatch'){ tree.tag = 'substrings'; + var split = tree.value.split("*"); + + //if the value string doesn't start with a * then theres no initial value + //else split will have an empty string in its first array index... + //we need to remove that empty string if(tree.value.indexOf("*") != 0){ tree.initial = split.shift(); }else{ split.shift(); } + + //if the value string doesn't end with a * then theres no final value + //also same split stuff as the initial stuff above if(tree.value.lastIndexOf("*") != tree.value.length-1){ tree['final'] = split.pop(); }else{ @@ -226,7 +173,7 @@ function _buildFilterTree(expr){ }; var treeToObjs = function(tree,filterObj){ - console.log("in treeToObjs"); + //console.log("in treeToObjs"); if(tree === undefined){ return filterObj; } @@ -235,6 +182,7 @@ var treeToObjs = function(tree,filterObj){ return filterObj; } + //if the current tree object is not an expression then its a logical operator (ie an internal node in the tree) var currentFilter = filterObj; if(tree.op != "expr"){ console.log("adding "+tree.op+" to filters"); @@ -254,36 +202,38 @@ var treeToObjs = function(tree,filterObj){ treeToObjs(child,currentFilter); } }else{ + //else its a leaf node in the tree, and represents some type of non-logical expression var tempFilter; - //console.log("adding "+tree.tag+" to filters"); + + //convert the tag name to a filter class type switch(tree.tag){ case "approxMatch": tempFilter = new ApproximateFilter({ attribute: tree.name, value: tree.value }); - console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); + //console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); break; case "greaterOrEqual": tempFilter = new GreaterThanEqualsFilter({ attribute: tree.name, value: tree.value }); - console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); + //console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); break; case "lessOrEqual": tempFilter = new LessThanEqualsFilter({ attribute: tree.name, value: tree.value }); - console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); + //console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); break; case "equalityMatch": tempFilter = new EqualityFilter({ attribute: tree.name, value: tree.value }); - console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); + //console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value); break; case "substrings": tempFilter = new SubstringFilter({ @@ -292,13 +242,13 @@ var treeToObjs = function(tree,filterObj){ any: tree.any, "final": tree["final"] }); - console.log("adding "+tree.tag+"; attr: "+tree.name+"; initial: "+tree.initial+"; any: "+JSON.stringify(tree.any) + "; final: "+tree['final']); + //console.log("adding "+tree.tag+"; attr: "+tree.name+"; initial: "+tree.initial+"; any: "+JSON.stringify(tree.any) + "; final: "+tree['final']); break; case "present": tempFilter = new PresenceFilter({ attribute: tree.name }); - console.log("adding "+tree.tag+"; attr: "+tree.name); + //console.log("adding "+tree.tag+"; attr: "+tree.name); break; } filterObj.addFilter(tempFilter); @@ -308,130 +258,20 @@ var treeToObjs = function(tree,filterObj){ function _parseString(str){ assert.ok(str); + //create a blank object to pass into treeToObjs + //since its recursive we have to prime it ourselves. + //this gets stripped off before the filter structure is returned + //at the bottom of this function. var filterObj = new AndFilter({ filters:[] }); var tree = _buildFilterTree(str); - console.log("tree built: ",JSON.stringify(tree)); + //console.log("tree built: ",JSON.stringify(tree)); treeToObjs(tree,filterObj); return filterObj.filters[0]; }; -/* -function _parseString(str) { - assert.ok(str); - - var stack = _filterStringToStack(str); - - if (!stack || !stack.length) - throw new Error('Invalid filter: ' + str); - - debugger; - var f; - var filters = []; - for (var i = stack.length - 1; i >= 0; i--) { - if (stack[i] === '&') { - filters.unshift(new AndFilter({ - filters: filters - })); - filters.length = 1; - } else if (stack[i] === '|') { - filters.unshift(new OrFilter({ - filters: filters - })); - filters.length = 1; - } else if (stack[i] === '!') { - filters.push(new NotFilter({ - filter: filters.pop() - })); - } else { - switch (stack[i].op) { - case '=': // could be presence, equality, substr or ext - if (stack[i].value === '*') { - filters.push(new PresenceFilter(stack[i])); - } else { - var vals = ['']; - var ndx = 0; - var esc = false; - for (var j = 0; j < stack[i].value.length; j++) { - var c = stack[i].value[j]; - if (c === '\\') { - if (esc) { - esc = true; - } else { - vals[ndx] += c; - esc = false; - } - } else if (c === '*') { - if (esc) { - vals[ndx] = c; - } else { - vals[++ndx] = ''; - } - } else { - vals[ndx] += c; - } - } - if (vals.length === 1) { - if (stack[i].attribute.indexOf(':') !== -1) { - var extTmp = stack[i].attribute.split(':'); - var extOpts = {}; - extOpts.matchType = extTmp[0]; - switch (extTmp.length) { - case 2: - break; - case 3: - if (extTmp[1].toLowerCase() === 'dn') { - extOpts.dnAttributes = true; - } else { - extOpts.rule = extTmp[1]; - } - break; - case 4: - extOpts.dnAttributes = true; - extOpts.rule = extTmp[2]; - break; - default: - throw new Error('Invalid extensible filter'); - } - extOpts.value = vals[0]; - filters.push(new ExtensibleFilter(extOpts)); - } else { - filters.push(new EqualityFilter(stack[i])); - } - } else { - filters.push(new SubstringFilter({ - attribute: stack[i].attribute, - initial: vals.shift() || null, - 'final': vals.pop() || null, - any: vals || null - })); - } - } - break; - case '~': - filters.push(new ApproximateFilter(stack[i])); - break; - case '>': - filters.push(new GreaterThanEqualsFilter(stack[i])); - break; - case '<': - filters.push(new LessThanEqualsFilter(stack[i])); - break; - default: - throw new Error('Invalid filter (op=' + stack[i].op + '): ' + str); - } - } - } - - if (filters.length !== 1) - throw new Error('Invalid filter: ' + str); - - return filters.pop(); -} -*/ - /* * A filter looks like this coming in: * Filter ::= CHOICE { From fb63ba2220c94d4d3a4487873ee58a768274b5a4 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 14:00:14 -0800 Subject: [PATCH 07/24] lint cleanup, and extensible matching --- lib/filters/index.js | 498 +++++++++++++++++++++------------------- lib/server.js | 14 +- tst/filters/ext.test.js | 1 + 3 files changed, 268 insertions(+), 245 deletions(-) diff --git a/lib/filters/index.js b/lib/filters/index.js index 6a7d07d..9e08f05 100644 --- a/lib/filters/index.js +++ b/lib/filters/index.js @@ -28,249 +28,271 @@ var BerReader = asn1.BerReader; ///--- Internal Parsers -//expression parsing -//returns the index of the closing parenthesis matching the open paren specified by openParenIndex -function matchParens(str, openParenIndex){ - var stack = []; - - for(var i=openParenIndex || 0;i - //so thats why its named tag, if you were wondering... - var operatorStr = ""; - var valueOffset=0; - tree.name = ""; - tree.value = ''; - if(expr.indexOf('~=') !=-1 ){ - operatorStr = '~='; - tree.tag = 'approxMatch'; - valueOffset = 2; - }else if(expr.indexOf('>=') != -1){ - operatorStr = '>='; - tree.tag = 'greaterOrEqual'; - valueOffset = 2; - }else if(expr.indexOf('<=') != -1){ - operatorStr = '<='; - tree.tag = 'lessOrEqual'; - valueOffset = 2; - }else if(expr.indexOf("=") != -1){ - operatorStr = '='; - tree.tag = 'equalityMatch'; - valueOffset = 1; - }else { - tree.tag = 'present'; - } - console.log('operatorStr: ' + operatorStr + '; valueOffset: ' + valueOffset); - if (operatorStr == ""){ - tree.name = expr; - }else{ - //pull out lhs and rhs of equality operator - //var index = expr.indexOf('='); - - var splitAry = expr.split(operatorStr,2); - tree.name =splitAry[0]; - tree.value = splitAry[1]; - - //substrings fall into the equality bin in the switch above - //so we need another check here to look for * - if (tree.value.indexOf('*') != -1 && tree.tag == 'equalityMatch'){ - tree.tag = 'substrings'; - - var split = tree.value.split("*"); - - //if the value string doesn't start with a * then theres no initial value - //else split will have an empty string in its first array index... - //we need to remove that empty string - if(tree.value.indexOf("*") != 0){ - tree.initial = split.shift(); - }else{ - split.shift(); - } - - //if the value string doesn't end with a * then theres no final value - //also same split stuff as the initial stuff above - if(tree.value.lastIndexOf("*") != tree.value.length-1){ - tree['final'] = split.pop(); - }else{ - split.pop(); - } - tree.any = split; - } - if(tree.value.length == 0){ - tree.tag = 'present'; - } - } - } - - return tree; -}; +// recursive function that builds a filter tree from a string expression +// the filter tree is an intermediary step between the incoming expression and +// the outgoing Filter Class structure. +function _buildFilterTree(expr) { + var tree = {}; + var split; -var treeToObjs = function(tree,filterObj){ - //console.log("in treeToObjs"); - if(tree === undefined){ - return filterObj; - } - - if(tree.length === 0){ - return filterObj; - } - - //if the current tree object is not an expression then its a logical operator (ie an internal node in the tree) - var currentFilter = filterObj; - if(tree.op != "expr"){ - console.log("adding "+tree.op+" to filters"); - switch (tree.op){ - case "and": - filterObj.addFilter(currentFilter = new AndFilter({filters:[]})); - break; - case "or": - filterObj.addFilter(currentFilter = new OrFilter({filters:[]})); - break; - case "not": - filterObj.addFilter(currentFilter = new NotFilter({filters:[]})); - break; - } - for(var i = 0,tempFilter,child;i + // so thats why its named tag, if you were wondering... + var operatorStr = ''; + var valueOffset = 0; + tree.name = ''; + tree.value = ''; + if (expr.indexOf('~=') !== -1) { + operatorStr = '~='; + tree.tag = 'approxMatch'; + valueOffset = 2; + } else if (expr.indexOf('>=') !== -1) { + operatorStr = '>='; + tree.tag = 'greaterOrEqual'; + valueOffset = 2; + } else if (expr.indexOf('<=') !== -1) { + operatorStr = '<='; + tree.tag = 'lessOrEqual'; + valueOffset = 2; + } else if (expr.indexOf(':=') !== -1) { + operatorStr = ':='; + tree.tag = 'extensibleMatch'; + valueOffset = 2; + } else if (expr.indexOf('=') !== -1) { + operatorStr = '='; + tree.tag = 'equalityMatch'; + valueOffset = 1; + } else { + tree.tag = 'present'; + } + + if (operatorStr === '') { + tree.name = expr; + } else { + // pull out lhs and rhs of equality operator + var splitAry = expr.split(operatorStr, 2); + tree.name = splitAry[0]; + tree.value = splitAry[1]; + + // substrings and extensible matching fall into the equality bin in the + // switch above so we need more processing here + if (tree.tag === 'equalityMatch') { + if (tree.value.indexOf('*') !== -1) { + tree.tag = 'substrings'; + + split = tree.value.split('*'); + + // if the value string doesn't start with a * then theres no initial + // value else split will have an empty string in its first array + // index... + // we need to remove that empty string + if (tree.value.indexOf('*') !== 0) { + tree.initial = split.shift(); + } else { + split.shift(); + } + + //if the value string doesn't end with a * then theres no final value + //also same split stuff as the initial stuff above + if (tree.value.lastIndexOf('*') !== tree.value.length - 1) { + tree['final'] = split.pop(); + } else { + split.pop(); + } + tree.any = split; + } else if (tree.value.length === 0) { + tree.tag = 'present'; + } + } else if (tree.tag == 'extensibleMatch') { + split = tree.name.split(':'); + console.log(split) + tree.extensible = { + matchType: split[0], + value: tree.value + }; + switch (split.length) { + case 1: + break; + case 2: + if (split[1].toLowerCase() === 'dn') { + tree.extensible.dnAttributes = true; + } else { + tree.extensible.rule = split[1]; + } + break; + case 3: + tree.extensible.dnAttributes = true; + tree.extensible.rule = split[2]; + break; + default: + throw new Error('Invalid extensible filter'); + } + } + } + } + + return tree; +} -function _parseString(str){ - assert.ok(str); - //create a blank object to pass into treeToObjs - //since its recursive we have to prime it ourselves. - //this gets stripped off before the filter structure is returned - //at the bottom of this function. - var filterObj = new AndFilter({ - filters:[] - }); - - var tree = _buildFilterTree(str); - //console.log("tree built: ",JSON.stringify(tree)); - treeToObjs(tree,filterObj); - return filterObj.filters[0]; -}; +function serializeTree(tree, filter) { + if (tree === undefined || tree.length === 0) + return filter; + + // if the current tree object is not an expression then its a logical + // operator (ie an internal node in the tree) + var current = null; + if (tree.op !== 'expr') { + switch (tree.op) { + case 'and': + current = new AndFilter(); + break; + case 'or': + current = new OrFilter(); + break; + case 'not': + current = new NotFilter(); + break; + } + + filter.addFilter(current || filter); + if (current || tree.children.length) { + tree.children.forEach(function(child) { + serializeTree(child, current); + }); + } + } else { + // else its a leaf node in the tree, and represents some type of + // non-logical expression + var tmp; + + // convert the tag name to a filter class type + switch (tree.tag) { + case 'approxMatch': + tmp = new ApproximateFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'extensibleMatch': + tmp = new ExtensibleFilter(tree.extensible); + break; + case 'greaterOrEqual': + tmp = new GreaterThanEqualsFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'lessOrEqual': + tmp = new LessThanEqualsFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'equalityMatch': + tmp = new EqualityFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'substrings': + tmp = new SubstringFilter({ + attribute: tree.name, + initial: tree.initial, + any: tree.any, + 'final': tree['final'] + }); + break; + case 'present': + tmp = new PresenceFilter({ + attribute: tree.name + }); + break; + } + filter.addFilter(tmp); + } +} + + +function _parseString(str) { + assert.ok(str); + + // create a blank object to pass into treeToObjs + // since its recursive we have to prime it ourselves. + // this gets stripped off before the filter structure is returned + // at the bottom of this function. + var filterObj = new AndFilter({ + filters: [] + }); + + serializeTree(_buildFilterTree(str), filterObj); + return filterObj.filters[0]; +} + /* * A filter looks like this coming in: diff --git a/lib/server.js b/lib/server.js index 9bc4b15..9354fde 100644 --- a/lib/server.js +++ b/lib/server.js @@ -425,14 +425,14 @@ function Server(options) { log.trace('data on %s: %s', c.ldap.id, util.inspect(data)); try { - c.parser.write(data); + c.parser.write(data); } catch (e) { - log.warn('Unable to parse message [c.on(\'data\')]: %s', e.stack); - c.end(new LDAPResult({ - status: 0x02, - errorMessage: e.toString(), - connection: c - }).toBer()); + log.warn('Unable to parse message [c.on(\'data\')]: %s', e.stack); + c.end(new LDAPResult({ + status: 0x02, + errorMessage: e.toString(), + connection: c + }).toBer()); } }); diff --git a/tst/filters/ext.test.js b/tst/filters/ext.test.js index c5ce806..07ae381 100644 --- a/tst/filters/ext.test.js +++ b/tst/filters/ext.test.js @@ -108,3 +108,4 @@ test('parse RFC example 5', function(t) { t.ok(f.dnAttributes); t.end(); }); + From 512541bfbd91d0c2e840d70013eb310dc1fe9d61 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 14:19:06 -0800 Subject: [PATCH 08/24] GH-50 Allow = in filter strings --- lib/filters/index.js | 28 ++++++++++++++++------------ tst/filters/parse.test.js | 12 ++++++++++++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/filters/index.js b/lib/filters/index.js index 9e08f05..f54a474 100644 --- a/lib/filters/index.js +++ b/lib/filters/index.js @@ -33,15 +33,23 @@ var BerReader = asn1.BerReader; // specified by openParenIndex function matchParens(str, openParenIndex) { var stack = []; - + var esc = false; for (var i = openParenIndex || 0; i < str.length; i++) { - if (str.charAt(i) === '(') { + var c = str[i]; + + if (c === '\\') { + if (!esc) + esc = true; + continue; + } else if (c === '(' && !esc) { stack.push(1); - } else if (str.charAt(i) === ')') { + } else if (c === ')' && !esc) { stack.pop(); if (stack.length === 0) return i; } + + esc = false; } return str.length - 1; @@ -58,6 +66,7 @@ function _buildFilterTree(expr) { if (expr.length === 0) return tree; + // Chop the parens (the call to matchParens below gets rid of the trailer) if (expr.charAt(0) == '(') expr = expr.substring(1, expr.length - 1); @@ -97,11 +106,6 @@ function _buildFilterTree(expr) { } } else { //else its some sort of non-logical expression, parse and return as such - - // tag represents the name of the operator, initially this library was used - // to encode a filter string into DSML where the tag name would be - // - // so thats why its named tag, if you were wondering... var operatorStr = ''; var valueOffset = 0; tree.name = ''; @@ -134,9 +138,10 @@ function _buildFilterTree(expr) { tree.name = expr; } else { // pull out lhs and rhs of equality operator - var splitAry = expr.split(operatorStr, 2); - tree.name = splitAry[0]; - tree.value = splitAry[1]; + + var splitAry = expr.split(operatorStr); + tree.name = splitAry.shift(); + tree.value = splitAry.join(operatorStr); // substrings and extensible matching fall into the equality bin in the // switch above so we need more processing here @@ -169,7 +174,6 @@ function _buildFilterTree(expr) { } } else if (tree.tag == 'extensibleMatch') { split = tree.name.split(':'); - console.log(split) tree.extensible = { matchType: split[0], value: tree.value diff --git a/tst/filters/parse.test.js b/tst/filters/parse.test.js index 12da35d..aee05ff 100644 --- a/tst/filters/parse.test.js +++ b/tst/filters/parse.test.js @@ -17,3 +17,15 @@ test('GH-48 XML Strings in filter', function(t) { }); t.end(); }); + + +test('GH-50 = in filter', function(t) { + var str = '(uniquemember=uuid=930896af-bf8c-48d4-885c-6573a94b1853, ' + + 'ou=users, o=smartdc)'; + var 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(); +}); From 11b3a6655d29cf3248c995843a443603eed31226 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 15:12:19 -0800 Subject: [PATCH 09/24] Support escaping * in filter values --- lib/filters/index.js | 97 ++++++++++++++++++++++++++++----------- tst/filters/parse.test.js | 50 ++++++++++++++++++++ tst/laundry.test.js | 2 +- 3 files changed, 122 insertions(+), 27 deletions(-) diff --git a/lib/filters/index.js b/lib/filters/index.js index f54a474..2d4379f 100644 --- a/lib/filters/index.js +++ b/lib/filters/index.js @@ -138,40 +138,67 @@ function _buildFilterTree(expr) { tree.name = expr; } else { // pull out lhs and rhs of equality operator - + var clean = false; var splitAry = expr.split(operatorStr); tree.name = splitAry.shift(); tree.value = splitAry.join(operatorStr); - // substrings and extensible matching fall into the equality bin in the + // substrings fall into the equality bin in the // switch above so we need more processing here if (tree.tag === 'equalityMatch') { - if (tree.value.indexOf('*') !== -1) { - tree.tag = 'substrings'; - - split = tree.value.split('*'); - - // if the value string doesn't start with a * then theres no initial - // value else split will have an empty string in its first array - // index... - // we need to remove that empty string - if (tree.value.indexOf('*') !== 0) { - tree.initial = split.shift(); - } else { - split.shift(); - } - - //if the value string doesn't end with a * then theres no final value - //also same split stuff as the initial stuff above - if (tree.value.lastIndexOf('*') !== tree.value.length - 1) { - tree['final'] = split.pop(); - } else { - split.pop(); - } - tree.any = split; - } else if (tree.value.length === 0) { + if (tree.value.length === 0) { tree.tag = 'present'; + } else { + var substrNdx = 0; + var substr = false; + var esc = false; + + // Effectively a hand-rolled .shift() to support \* sequences + clean = true; + split = []; + substrNdx = 0; + split[substrNdx] = ''; + for (var i = 0; i < tree.value.length; i++) { + var c = tree.value[i]; + if (esc) { + split[substrNdx] += c; + esc = false; + } else if (c === '*') { + split[++substrNdx] = ''; + } else if (c === '\\') { + esc = true; + } else { + split[substrNdx] += c; + } + } + + if (split.length > 1) { + tree.tag = 'substrings'; + clean = true; + + // if the value string doesn't start with a * then theres no initial + // value else split will have an empty string in its first array + // index... + // we need to remove that empty string + if (tree.value.indexOf('*') !== 0) { + tree.initial = split.shift(); + } else { + split.shift(); + } + + // if the value string doesn't end with a * then theres no final + // value also same split stuff as the initial stuff above + if (tree.value.lastIndexOf('*') !== tree.value.length - 1) { + tree['final'] = split.pop(); + } else { + split.pop(); + } + tree.any = split; + } else { + tree.value = split[0]; // pick up the cleaned version + } } + } else if (tree.tag == 'extensibleMatch') { split = tree.name.split(':'); tree.extensible = { @@ -197,6 +224,24 @@ function _buildFilterTree(expr) { } } } + + // Cleanup any escape sequences + if (!clean) { + var val = ''; + var esc = false; + for (var i = 0; i < tree.value.length; i++) { + var c = tree.value[i]; + if (esc) { + val += c; + esc = false; + } else if (c === '\\') { + esc = true; + } else { + val += c; + } + } + tree.value = val; + } } return tree; diff --git a/tst/filters/parse.test.js b/tst/filters/parse.test.js index aee05ff..251376c 100644 --- a/tst/filters/parse.test.js +++ b/tst/filters/parse.test.js @@ -29,3 +29,53 @@ test('GH-50 = in filter', function(t) { 'uuid=930896af-bf8c-48d4-885c-6573a94b1853, ou=users, o=smartdc'); t.end(); }); + + +test('( in filter', function(t) { + var str = '(foo=bar\\()'; + var f = parse(str); + t.ok(f); + t.equal(f.attribute, 'foo'); + t.equal(f.value, 'bar('); + t.end(); +}); + + +test(') in filter', function(t) { + var str = '(foo=bar\\))'; + var f = parse(str); + t.ok(f); + t.equal(f.attribute, 'foo'); + t.equal(f.value, 'bar)'); + t.end(); +}); + + +test('\\ in filter', function(t) { + var str = '(foo=bar\\\\)'; + var f = parse(str); + t.ok(f); + t.equal(f.attribute, 'foo'); + t.equal(f.value, 'bar\\'); + t.end(); +}); + + +test('* in equality filter', function(t) { + var str = '(foo=bar\\*)'; + var f = parse(str); + t.ok(f); + t.equal(f.attribute, 'foo'); + t.equal(f.value, 'bar*'); + t.end(); +}); + + +test('* substr filter (prefix)', function(t) { + var str = '(foo=bar*)'; + var f = parse(str); + t.ok(f); + t.equal(f.attribute, 'foo'); + t.equal(f.initial, 'bar'); + t.end(); +}); diff --git a/tst/laundry.test.js b/tst/laundry.test.js index ee70cc0..d8aafc6 100644 --- a/tst/laundry.test.js +++ b/tst/laundry.test.js @@ -44,7 +44,7 @@ test('Evolution search filter (GH-3)', function(t) { }; server.search(suffix, function(req, res, next) { - console.log(req.filter.toString()); + console.log(req.filter.filters[0].type); if (req.filter.matches(entry.attributes)) res.send(entry); res.end(); From 87d7ef977ee9b802c5d07fb34c4e39a9eeb3b26a Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 15:15:34 -0800 Subject: [PATCH 10/24] version bump --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 01145ac..47d7497 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,13 @@ "contributors": [ "Mathieu Lecarme >", "Trent Mick ", - "Yunong Xiao " + "Yunong Xiao ", + "Craig Baker" ], "name": "ldapjs", "homepage": "http://ldapjs.org", "description": "LDAP client and server APIs", - "version": "0.4.4", + "version": "0.4.5", "repository": { "type": "git", "url": "git://github.com/mcavage/node-ldapjs.git" From 44a9d87863525d80801b68a6b5ff2b5c324bedcd Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 15:39:16 -0800 Subject: [PATCH 11/24] GH-49 Allow options.attributes = "dn" in client.search --- lib/client.js | 32 ++++++++++++----- tst/laundry.test.js | 87 ++++++++++++++++++++++++++++----------------- 2 files changed, 78 insertions(+), 41 deletions(-) diff --git a/lib/client.js b/lib/client.js index 1706675..a47da62 100644 --- a/lib/client.js +++ b/lib/client.js @@ -621,6 +621,15 @@ Client.prototype.search = function(base, options, controls, callback) { if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); + if (options.attributes) { + if (Array.isArray(options.attributes)) { + // noop + } else if (typeof(options.attributes) === 'string') { + options.attributes = [options.attributes]; + } else { + throw new TypeError('options.attributes must be an Array of Strings'); + } + } var req = new SearchRequest({ baseObject: typeof(base) === 'string' ? dn.parse(base) : base, scope: options.scope || 'base', @@ -633,6 +642,8 @@ Client.prototype.search = function(base, options, controls, callback) { controls: controls }); + + if (!this.connection) return callback(new ConnectionError('no connection')); @@ -698,18 +709,24 @@ Client.prototype._send = function(message, expect, callback, connection) { var self = this; - function closedConn() { - if (conn) - conn.destroy(); + function closeConn(err) { + var err = err || new ConnectionError('no connection'); + + // This is lame, but we want to send the original error back, whereas + // this will trigger a connection event + process.nextTick(function() { + if (conn) + conn.destroy(); + }); if (typeof(callback) === 'function') - return callback(new ConnectionError('no connection')); + return callback(err); - return callback.emit('error', new ConnectionError('no connection')); + return callback.emit('error', err); } if (!conn) - return closedConn(); + return closeConn(); // Now set up the callback in the messages table message.messageID = conn.ldap.nextMessageID; @@ -784,8 +801,7 @@ Client.prototype._send = function(message, expect, callback, connection) { try { return conn.write(message.toBer(), _writeCb); } catch (e) { - conn.end(); - return closedConn(); + return closeConn(e); } }; diff --git a/tst/laundry.test.js b/tst/laundry.test.js index d8aafc6..32d64ba 100644 --- a/tst/laundry.test.js +++ b/tst/laundry.test.js @@ -9,11 +9,36 @@ var ldap = require('../lib/index'); ///--- Globals var SOCKET = '/tmp/.' + uuid(); +var SUFFIX = 'dc=' + uuid(); var client; var server; + +///--- Helper + +function search(t, options, callback) { + client.search(SUFFIX, options, function(err, res) { + t.ifError(err); + t.ok(res); + var found = false; + res.on('searchEntry', function(entry) { + t.ok(entry); + found = true; + }); + res.on('end', function() { + t.ok(found); + if (callback) + return callback(); + + t.end(); + }); + }); +} + + + ///--- Tests test('setup', function(t) { @@ -24,32 +49,30 @@ test('setup', function(t) { socketPath: SOCKET }); t.ok(client); - // client.log4js.setLevel('Debug'); t.end(); }); + + server.search(SUFFIX, function(req, res, next) { + var entry = { + dn: 'cn=foo, ' + SUFFIX, + attributes: { + objectclass: ['person', 'top'], + cn: 'Pogo Stick', + sn: 'Stick', + givenname: 'ogo', + mail: uuid() + '@pogostick.org' + } + }; + + if (req.filter.matches(entry.attributes)) + res.send(entry); + + res.end(); + }); }); test('Evolution search filter (GH-3)', function(t) { - var suffix = 'dc=' + uuid(); - var entry = { - dn: 'cn=foo, ' + suffix, - attributes: { - objectclass: ['person', 'top'], - cn: 'Pogo Stick', - sn: 'Stick', - givenname: 'ogo', - mail: uuid() + '@pogostick.org' - } - }; - - server.search(suffix, function(req, res, next) { - console.log(req.filter.filters[0].type); - if (req.filter.matches(entry.attributes)) - res.send(entry); - res.end(); - }); - // This is what Evolution sends, when searching for a contact 'ogo'. Wow. var filter = '(|(cn=ogo*)(givenname=ogo*)(sn=ogo*)(mail=ogo*)(member=ogo*)' + @@ -69,19 +92,17 @@ test('Evolution search filter (GH-3)', function(t) { '(anniversary=ogo*)(birthdate=ogo*)(mailer=ogo*)(fileas=ogo*)' + '(category=ogo*)(calcaluri=ogo*)(calfburl=ogo*)(icscalendar=ogo*))'; - client.search(suffix, filter, function(err, res) { - t.ifError(err); - t.ok(res); - var found = false; - res.on('searchEntry', function(entry) { - t.ok(entry); - found = true; - }); - res.on('end', function() { - t.ok(found); - t.end(); - }); - }); + return search(t, filter); +}); + + +test('GH-49 Client errors on bad attributes', function(t) { + var searchOpts = { + filter: 'cn=*ogo*', + scope: 'one', + attributes: 'dn' + }; + return search(t, searchOpts); }); From f7276475b9d6e7c4dc2a7adb6d9861338faacd70 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 18:02:10 -0800 Subject: [PATCH 12/24] GH-51 Timeout support in client library --- bin/ldapjs-search | 10 ++- docs/client.md | 11 +++- lib/client.js | 145 +++++++++++++++++++++++++++----------------- tst/client.test.js | 13 ++++ tst/laundry.test.js | 2 +- 5 files changed, 122 insertions(+), 59 deletions(-) diff --git a/bin/ldapjs-search b/bin/ldapjs-search index e0d7391..06fd75a 100755 --- a/bin/ldapjs-search +++ b/bin/ldapjs-search @@ -38,6 +38,7 @@ var opts = { 'password': String, 'persistent': Boolean, 'scope': String, + 'timeout': Number, 'url': url }; @@ -49,6 +50,7 @@ var shortOpts = { 'w': ['--password'], 'p': ['--persistent'], 's': ['--scope'], + 't': ['--timeout'], 'u': ['--url'] }; @@ -129,13 +131,19 @@ if (!parsed.persistent) var client = ldap.createClient({ url: parsed.url, - log4js: log4js + log4js: log4js, + timeout: parsed.timeout || false }); client.on('error', function(err) { perror(err); }); +client.on('timeout', function(req) { + process.stderr.write('Timeout reached\n'); + process.exit(1); +}); + client.bind(parsed.binddn, parsed.password, function(err, res) { if (err) perror(err); diff --git a/docs/client.md b/docs/client.md index fbbda2e..b38b551 100644 --- a/docs/client.md +++ b/docs/client.md @@ -28,7 +28,8 @@ client is: ||url|| a valid LDAP url.|| ||socketPath|| If you're running an LDAP server over a Unix Domain Socket, use this.|| ||log4js|| You can optionally pass in a log4js instance the client will use to acquire a logger. The client logs all messages at the `Trace` level.|| -||numConnections||The size of the connection pool. Default is 1.|| +||timeout||How long the client should let operations live for before timing out. Default is Infinity.|| +||connectTimeout||How long the client should wait before timing out on TCP connections. Default is up to the OS.|| ||reconnect||Whether or not to automatically reconnect (and rebind) on socket errors. Takes amount of time in millliseconds. Default is 1000. 0/false will disable altogether.|| ## Connection management @@ -45,6 +46,14 @@ operations be allowed back through; in the meantime all callbacks will receive a `DisconnectedError`. If you never called `bind`, the client will allow operations when the socket is connected. +Also, note that the client will emit a `timeout` event if an operation +times out, and you'll be passed in the request object that was offending. You +probably don't _need_ to listen on it, as the client will also return an error +in the callback of that request. However, it is useful if you want to have a +catch-all. An event of `connectTimout` will be emitted when the client fails to +get a socket in time; there are no arguments. Note that this event will be +emitted (potentially) in reconnect scenarios as well. + ## Common patterns The last two parameters in every API are `controls` and `callback`. `controls` diff --git a/lib/client.js b/lib/client.js index a47da62..9f0618f 100644 --- a/lib/client.js +++ b/lib/client.js @@ -124,13 +124,18 @@ function Client(options) { this.secure = this.url.secure; } - this.log4js = options.log4js || logStub; + this.connection = null; + this.connectTimeout = options.connectTimeout || false; this.connectOptions = { port: self.url ? self.url.port : options.socketPath, host: self.url ? self.url.hostname : undefined, socketPath: options.socketPath || undefined }; + this.log4js = options.log4js || logStub; + this.reconnect = (typeof(options.reconnect) === 'number' ? + options.reconnect : 1000); this.shutdown = false; + this.timeout = options.timeout || false; this.__defineGetter__('log', function() { if (!self._log) @@ -139,11 +144,7 @@ function Client(options) { return self._log; }); - this.reconnect = (typeof(options.reconnect) === 'number' ? - options.reconnect : 1000); - - this.connection = null; - this.connect(); + return this.connect(function() {}); } util.inherits(Client, EventEmitter); module.exports = Client; @@ -157,24 +158,39 @@ module.exports = Client; */ Client.prototype.connect = function(callback) { if (this.connection) - return; + return callback(); var self = this; - var connection = this.connection = this._newConnection(); + var timer = false; + if (this.connectTimeout) { + timer = setTimeout(function() { + if (self.connection) + self.connection.destroy(); + + var err = new ConnectionError('timeout'); + self.emit('connectTimeout'); + return callback(err); + }, this.connectTimeout); + } + + this.connection = this._newConnection(); function reconnect() { self.connection = null; if (self.reconnect) - setTimeout(function() { self.connect(); }, self.reconnect); + setTimeout(function() { self.connect(function() {}); }, self.reconnect); } - this.connection.on('close', function(had_err) { + self.connection.on('close', function(had_err) { self.emit('close', had_err); reconnect(); }); - this.connection.on('connect', function() { + self.connection.on('connect', function() { + if (timer) + clearTimeout(timer); + if (self._bindDN && self._credentials) return self.bind(self._bindDN, self._credentials, function(err) { if (err) { @@ -183,9 +199,11 @@ Client.prototype.connect = function(callback) { } self.emit('connect'); + return callback(); }); self.emit('connect'); + return callback(); }); }; @@ -214,24 +232,25 @@ Client.prototype.bind = function(name, credentials, controls, callback, conn) { if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); - this.connect(); + var self = this; + this.connect(function() { + var req = new BindRequest({ + name: name || '', + authentication: 'Simple', + credentials: credentials || '', + controls: controls + }); - var req = new BindRequest({ - name: name || '', - authentication: 'Simple', - credentials: credentials || '', - controls: controls + return self._send(req, [errors.LDAP_SUCCESS], function(err, res) { + if (!err) { // In case we need to reconnect later + self._bindDN = name; + self._credentials = credentials; + } + + return callback(err, res); + }, conn); }); - - return self._send(req, [errors.LDAP_SUCCESS], function(err, res) { - if (!err) { // In case we need to reconnect later - self._bindDN = name; - self._credentials = credentials; - } - - return callback(err, res); - }, conn); }; @@ -691,7 +710,7 @@ Client.prototype.unbind = function(callback) { this._bindDN = null; this._credentials = null; - if (!this.connect) + if (!this.connection) return callback(); var req = new UnbindRequest(); @@ -708,21 +727,22 @@ Client.prototype._send = function(message, expect, callback, connection) { var conn = connection || this.connection; var self = this; + var timer; function closeConn(err) { + if (timer) + clearTimeout(timer); + var err = err || new ConnectionError('no connection'); - // This is lame, but we want to send the original error back, whereas - // this will trigger a connection event - process.nextTick(function() { - if (conn) - conn.destroy(); - }); + if (typeof(callback) === 'function') { + callback(err); + } else { + callback.emit('error', err); + } - if (typeof(callback) === 'function') - return callback(err); - - return callback.emit('error', err); + if (conn) + conn.destroy(); } if (!conn) @@ -731,7 +751,10 @@ Client.prototype._send = function(message, expect, callback, connection) { // Now set up the callback in the messages table message.messageID = conn.ldap.nextMessageID; if (expect !== 'abandon') { - conn.ldap.messages[message.messageID] = function(res) { + conn.ldap.messages[message.messageID] = function _sendCallback(res) { + if (timer) + clearTimeout(timer); + if (self.log.isDebugEnabled()) self.log.debug('%s: response received: %j', conn.ldap.id, res.json); @@ -778,27 +801,36 @@ Client.prototype._send = function(message, expect, callback, connection) { }; } - // Finally send some data - if (this.log.isDebugEnabled()) - this.log.debug('%s: sending request: %j', conn.ldap.id, message.json); - - // Note if this was an unbind, we just go ahead and end, since there - // will never be a response - var _writeCb = null; - if (expect === 'abandon') { - _writeCb = function() { - return callback(); - }; - } else if (expect === 'unbind') { - _writeCb = function() { - conn.unbindMessageID = message.id; - conn.end(); - }; - } else { - // noop + // If there's a user specified timeout, pick that up + if (this.timeout) { + timer = setTimeout(function() { + self.emit('timeout', message); + if (conn.ldap.messages[message.messageID]) + return conn.ldap.messages[message.messageID](new LDAPResult({ + status: 80, // LDAP_OTHER + errorMessage: 'request timeout (client interrupt)' + })); + }, this.timeout); } try { + // Note if this was an unbind, we just go ahead and end, since there + // will never be a response + var _writeCb = null; + if (expect === 'abandon') { + _writeCb = function() { + return callback(); + }; + } else if (expect === 'unbind') { + _writeCb = function() { + conn.unbindMessageID = message.id; + conn.end(); + }; + } + + // Finally send some data + if (this.log.isDebugEnabled()) + this.log.debug('%s: sending request: %j', conn.ldap.id, message.json); return conn.write(message.toBer(), _writeCb); } catch (e) { return closeConn(e); @@ -906,6 +938,7 @@ Client.prototype._newConnection = function() { if (log.isTraceEnabled()) log.trace('%s timeout event=%s', c.ldap.id); + self.emit('timeout'); c.end(); }); diff --git a/tst/client.test.js b/tst/client.test.js index ec69f0d..84cbec2 100644 --- a/tst/client.test.js +++ b/tst/client.test.js @@ -75,6 +75,10 @@ test('setup', function(t) { return next(); }); + server.search('dc=timeout', function(req, res, next) { + // Haha client! + }); + server.search(SUFFIX, function(req, res, next) { if (req.dn.equals('cn=ref,' + SUFFIX)) { @@ -575,6 +579,15 @@ test('unbind (GH-30)', function(t) { }); +test('search timeout (GH-51)', function(t) { + client.timeout = 250; + client.search('dc=timeout', 'objectclass=*', function(err, res) { + t.ok(err); + t.end(); + }); +}); + + test('shutdown', function(t) { client.unbind(function(err) { server.on('close', function() { diff --git a/tst/laundry.test.js b/tst/laundry.test.js index 32d64ba..4b6401b 100644 --- a/tst/laundry.test.js +++ b/tst/laundry.test.js @@ -63,7 +63,7 @@ test('setup', function(t) { mail: uuid() + '@pogostick.org' } }; - + if (req.filter.matches(entry.attributes)) res.send(entry); From c727ac922f7e958c1f37b656de729e6a905ddd25 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Thu, 19 Jan 2012 18:03:44 -0800 Subject: [PATCH 13/24] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 47d7497..35aa42d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "ldapjs", "homepage": "http://ldapjs.org", "description": "LDAP client and server APIs", - "version": "0.4.5", + "version": "0.4.6", "repository": { "type": "git", "url": "git://github.com/mcavage/node-ldapjs.git" From 0e30dc50c4e7711b7e827e5570e303923fa0c9a6 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Tue, 24 Jan 2012 08:56:30 -0800 Subject: [PATCH 14/24] GH-53 unable to parse !filters --- Makefile | 3 ++- lib/filters/not_filter.js | 20 ++++++++++++++------ tst/filters/not.test.js | 7 +------ tst/filters/parse.test.js | 15 +++++++++++++++ 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index bba4676..b3ed682 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ RESTDOWN = ./node_modules/.restdown/bin/restdown \ -m ${DOCPKGDIR} \ -D mediaroot=media -.PHONY: dep lint test doc clean all +.PHONY: dep lint test doc clean all install all:: test doc @@ -38,6 +38,7 @@ node_modules/.ldapjs.npm.installed: @touch ./node_modules/.ldapjs.npm.installed dep: ./node_modules/.ldapjs.npm.installed +install: dep gjslint: gjslint --nojsdoc -r lib -r tst diff --git a/lib/filters/not_filter.js b/lib/filters/not_filter.js index e973412..a473a9a 100644 --- a/lib/filters/not_filter.js +++ b/lib/filters/not_filter.js @@ -12,16 +12,18 @@ var Protocol = require('../protocol'); ///--- API function NotFilter(options) { - if (typeof(options) !== 'object') - throw new TypeError('options (object) required'); - if (!options.filter || !(options.filter instanceof Filter)) - throw new TypeError('options.filter (Filter) required'); + if (typeof(options) === 'object') { + if (!options.filter || !(options.filter instanceof Filter)) + throw new TypeError('options.filter (Filter) required'); + } else { + options = {}; + } + + this.filter = options.filter || {}; options.type = Protocol.FILTER_NOT; Filter.call(this, options); - this.filter = options.filter; - var self = this; this.__defineGetter__('json', function() { return { @@ -34,6 +36,12 @@ util.inherits(NotFilter, Filter); module.exports = NotFilter; +NotFilter.prototype.addFilter = function(f) { + if (!(f instanceof Filter)) + throw new TypeError('filter (Filter) required'); + this.filter = f; +}; + NotFilter.prototype.toString = function() { return '(!' + this.filter.toString() + ')'; }; diff --git a/tst/filters/not.test.js b/tst/filters/not.test.js index 48c17aa..50b729d 100644 --- a/tst/filters/not.test.js +++ b/tst/filters/not.test.js @@ -26,12 +26,7 @@ test('load library', function(t) { test('Construct no args', function(t) { - try { - new NotFilter(); - t.fail('should have thrown'); - } catch (e) { - t.ok(e instanceof TypeError); - } + t.ok(new NotFilter()); t.end(); }); diff --git a/tst/filters/parse.test.js b/tst/filters/parse.test.js index 251376c..56c2fce 100644 --- a/tst/filters/parse.test.js +++ b/tst/filters/parse.test.js @@ -79,3 +79,18 @@ test('* substr filter (prefix)', function(t) { t.equal(f.initial, 'bar'); t.end(); }); + + +test('GH-53 NotFilter', function(t) { + var str = '(&(objectClass=person)(!(objectClass=shadowAccount)))'; + var 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(); +}); From a499a7cfd54808e71d612d2e54b17dd5b59340bf Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Tue, 24 Jan 2012 09:43:46 -0800 Subject: [PATCH 15/24] Addition of javascriptlint --- Makefile | 25 +++++--- lib/attribute.js | 3 +- lib/client.js | 34 ++++++----- lib/server.js | 10 ++-- tools/jsl.conf | 140 +++++++++++++++++++++++++++++++++++++++++++++ tst/change.test.js | 2 +- 6 files changed, 184 insertions(+), 30 deletions(-) create mode 100755 tools/jsl.conf diff --git a/Makefile b/Makefile index b3ed682..318c674 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,22 @@ -NAME=ldapjs ifeq ($(VERSION), "") @echo "Use gmake" endif +DOCPKGDIR = ./docs/pkg +HAVE_GJSLINT := $(shell which gjslint >/dev/null && echo yes || echo no) +LINT = ./node_modules/.javascriptlint/build/install/jsl --conf ./tools/jsl.conf +NAME=ldapjs +RESTDOWN_VERSION=1.2.13 SRC := $(shell pwd) TAR = tar UNAME := $(shell uname) ifeq ($(UNAME), SunOS) TAR = gtar endif - -HAVE_GJSLINT := $(shell which gjslint >/dev/null && echo yes || echo no) NPM := npm_config_tar=$(TAR) npm -RESTDOWN_VERSION=1.2.13 -DOCPKGDIR = ./docs/pkg - RESTDOWN = ./node_modules/.restdown/bin/restdown \ -b ./docs/branding \ -m ${DOCPKGDIR} \ @@ -34,7 +33,15 @@ node_modules/.ldapjs.npm.installed: else \ (cd node_modules/.restdown && git fetch origin); \ fi + + if [[ ! -d node_modules/.javascriptlint ]]; then \ + git clone https://github.com/davepacheco/javascriptlint node_modules/.javascriptlint; \ + else \ + (cd node_modules/.javascriptlint && git fetch origin); \ + fi + @(cd ./node_modules/.restdown && git checkout $(RESTDOWN_VERSION)) + @(cd ./node_modules/.javascriptlint && $(MAKE) install) @touch ./node_modules/.ldapjs.npm.installed dep: ./node_modules/.ldapjs.npm.installed @@ -44,13 +51,15 @@ gjslint: gjslint --nojsdoc -r lib -r tst ifeq ($(HAVE_GJSLINT), yes) -lint: gjslint +lint: install gjslint + ${LINT} --recurse lib/*.js else -lint: +lint: install @echo "* * *" @echo "* Warning: Cannot lint with gjslint. Install it from:" @echo "* http://code.google.com/closure/utilities/docs/linter_howto.html" @echo "* * *" + ${LINT} --recurse lib/*.js endif doc: dep diff --git a/lib/attribute.js b/lib/attribute.js index 8054f0b..5c5a7bd 100644 --- a/lib/attribute.js +++ b/lib/attribute.js @@ -148,9 +148,10 @@ Attribute.isAttribute = function(attr) { if (attr instanceof Attribute) return true; if (!attr.type || typeof(attr.type) !== 'string') return false; if (!attr.vals || !Array.isArray(attr.vals)) return false; - for (var i = 0; i < attr.vals.length; i++) + for (var i = 0; i < attr.vals.length; i++) { if (typeof(attr.vals[i]) !== 'string' && !Buffer.isBuffer(attr.vals[i])) return false; + } return true; }; diff --git a/lib/client.js b/lib/client.js index 9f0618f..22831cd 100644 --- a/lib/client.js +++ b/lib/client.js @@ -205,6 +205,8 @@ Client.prototype.connect = function(callback) { self.emit('connect'); return callback(); }); + + return false; }; @@ -227,7 +229,7 @@ Client.prototype.bind = function(name, credentials, controls, callback, conn) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -272,7 +274,7 @@ Client.prototype.abandon = function(messageID, controls, callback) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -308,7 +310,7 @@ Client.prototype.add = function(name, entry, controls, callback) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -366,7 +368,7 @@ Client.prototype.compare = function(name, attr, value, controls, callback) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -406,7 +408,7 @@ Client.prototype.del = function(name, controls, callback) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -447,7 +449,7 @@ Client.prototype.exop = function(name, value, controls, callback) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -520,7 +522,7 @@ Client.prototype.modify = function(name, change, controls, callback) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -558,7 +560,7 @@ Client.prototype.modifyDN = function(name, newName, controls, callback) { callback = controls; controls = []; } else { - control = validateControls(controls); + controls = validateControls(controls); } if (typeof(callback) !== 'function') throw new TypeError('callback (function) required'); @@ -672,11 +674,10 @@ Client.prototype.search = function(base, options, controls, callback) { // reconnected, and having thrown an error like "NotWriteable". Because // the event emitter logic will never block, we'll end up returning from // the event.on('error'), rather than "normally". - var self = this; var done = false; function errorIfNoConn(err) { if (done) - return; + return false; done = true; return callback(err); @@ -703,7 +704,7 @@ Client.prototype.unbind = function(callback) { if (callback && typeof(callback) !== 'function') throw new TypeError('callback must be a function'); if (!callback) - callback = function defUnbindCb() { self.log.trace('disconnected'); }; + callback = function() { self.log.trace('disconnected'); }; var self = this; this.reconnect = false; @@ -733,7 +734,7 @@ Client.prototype._send = function(message, expect, callback, connection) { if (timer) clearTimeout(timer); - var err = err || new ConnectionError('no connection'); + err = err || new ConnectionError('no connection'); if (typeof(callback) === 'function') { callback(err); @@ -751,7 +752,7 @@ Client.prototype._send = function(message, expect, callback, connection) { // Now set up the callback in the messages table message.messageID = conn.ldap.nextMessageID; if (expect !== 'abandon') { - conn.ldap.messages[message.messageID] = function _sendCallback(res) { + conn.ldap.messages[message.messageID] = function(res) { if (timer) clearTimeout(timer); @@ -798,6 +799,8 @@ Client.prototype._send = function(message, expect, callback, connection) { callback.emit('error', err); } + + return false; }; } @@ -806,7 +809,7 @@ Client.prototype._send = function(message, expect, callback, connection) { timer = setTimeout(function() { self.emit('timeout', message); if (conn.ldap.messages[message.messageID]) - return conn.ldap.messages[message.messageID](new LDAPResult({ + conn.ldap.messages[message.messageID](new LDAPResult({ status: 80, // LDAP_OTHER errorMessage: 'request timeout (client interrupt)' })); @@ -921,6 +924,7 @@ Client.prototype._newConnection = function() { delete c.ldap; delete c.parser; + return false; }); }); @@ -956,7 +960,7 @@ Client.prototype._newConnection = function() { if (!callback) { log.error('%s: unsolicited message: %j', c.ldap.id, message.json); - return; + return false; } return callback(message); diff --git a/lib/server.js b/lib/server.js index 9354fde..54fe285 100644 --- a/lib/server.js +++ b/lib/server.js @@ -349,7 +349,7 @@ function Server(options) { if (!res) { log.warn('Unimplemented server method: %s', req.type); c.destroy(); - return; + return false; } res.connection = c; @@ -417,7 +417,7 @@ function Server(options) { res.status = 0x02; // protocol error res.errorMessage = err.toString(); - c.end(res.toBer()); + return c.end(res.toBer()); }); c.on('data', function(data) { @@ -670,7 +670,7 @@ Server.prototype.listen = function(port, host, callback) { } if (typeof(callback) === 'function') - return callback(); + callback(); } if (typeof(port) === 'number') { @@ -680,8 +680,8 @@ Server.prototype.listen = function(port, host, callback) { } }; Server.prototype.listenFD = function(fd) { - self.host = 'unix-domain-socket'; - self.port = fd; + this.host = 'unix-domain-socket'; + this.port = fd; return this.server.listenFD(fd); }; Server.prototype.close = function() { diff --git a/tools/jsl.conf b/tools/jsl.conf new file mode 100755 index 0000000..119319e --- /dev/null +++ b/tools/jsl.conf @@ -0,0 +1,140 @@ +# +# Configuration File for JavaScript Lint 0.3.0 +# Developed by Matthias Miller (http://www.JavaScriptLint.com) +# +# This configuration file can be used to lint a collection of scripts, or to enable +# or disable warnings for scripts that are linted via the command line. +# + +### Warnings +# Enable or disable warnings based on requirements. +# Use "+WarningName" to display or "-WarningName" to suppress. +# ++no_return_value # function {0} does not always return a value ++duplicate_formal # duplicate formal argument {0} ++equal_as_assign # test for equality (==) mistyped as assignment (=)?{0} ++var_hides_arg # variable {0} hides argument ++redeclared_var # redeclaration of {0} {1} ++anon_no_return_value # anonymous function does not always return a value ++missing_semicolon # missing semicolon ++meaningless_block # meaningless block; curly braces have no impact ++comma_separated_stmts # multiple statements separated by commas (use semicolons?) +-unreachable_code # unreachable code ++missing_break # missing break statement ++missing_break_for_last_case # missing break statement for last case in switch ++comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) +-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement ++useless_void # use of the void type may be unnecessary (void is always undefined) +-useless_quotes # quotation marks are unnecessary ++multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs ++use_of_label # use of label +-block_without_braces # block statement without curly braces ++leading_decimal_point # leading decimal point may indicate a number or an object member ++trailing_decimal_point # trailing decimal point may indicate a number or an object member +-octal_number # leading zeros make an octal number ++nested_comment # nested comment ++misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma ++ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement ++empty_statement # empty statement or extra semicolon +-missing_option_explicit # the "option explicit" control comment is missing ++partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag ++dup_option_explicit # duplicate "option explicit" control comment ++useless_assign # useless assignment ++ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity ++ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent) +-missing_default_case # missing default case in switch statement ++duplicate_case_in_switch # duplicate case in switch statements ++default_not_at_end # the default case is not at the end of the switch statement ++legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax ++jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax ++useless_comparison # useless comparison; comparing identical expressions ++with_statement # with statement hides undeclared variables; use temporary variable instead ++trailing_comma_in_array # extra comma is not recommended in array initializers ++assign_to_function_call # assignment to a function call ++parseint_missing_radix # parseInt missing radix parameter ++unreferenced_argument # argument declared but never referenced: {name} ++unreferenced_function # function declared but not referenced +-identifier_hides_another +-empty_statement + +### Output format +# Customize the format of the error message. +# __FILE__ indicates current file path +# __FILENAME__ indicates current file name +# __LINE__ indicates current line +# __ERROR__ indicates error message +# +# Visual Studio syntax (default): ++output-format __FILE__(__LINE__): __ERROR__ +# Alternative syntax: +#+output-format __FILE__:__LINE__: __ERROR__ + + +### Context +# Show the in-line position of the error. +# Use "+context" to display or "-context" to suppress. +# ++context + + +### Semicolons +# By default, assignments of an anonymous function to a variable or +# property (such as a function prototype) must be followed by a semicolon. +# +#+lambda_assign_requires_semicolon # deprecated setting + + +### Control Comments +# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for +# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is +# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason, +# although legacy control comments are enabled by default for backward compatibility. +# ++legacy_control_comments + + +### JScript Function Extensions +# JScript allows member functions to be defined like this: +# function MyObj() { /*constructor*/ } +# function MyObj.prototype.go() { /*member function*/ } +# +# It also allows events to be attached like this: +# function window::onload() { /*init page*/ } +# +# This is a Microsoft-only JavaScript extension. Enable this setting to allow them. +# +#-jscript_function_extensions # deprecated setting + + +### Defining identifiers +# By default, "option explicit" is enabled on a per-file basis. +# To enable this for all files, use "+always_use_option_explicit" +-always_use_option_explicit + +# Define certain identifiers of which the lint is not aware. +# (Use this in conjunction with the "undeclared identifier" warning.) +# +# Common uses for webpages might be: ++define global ++define process ++define require ++define exports ++define setTimeout ++define clearTimeout ++define setInterval ++define clearInterval ++define JSON ++define console ++define __dirname ++define __filename ++define Buffer ++define module + + +### Files +# Specify which files to lint +# Use "+recurse" to enable recursion (disabled by default). +# To add a set of files, use "+process FileName", "+process Folder\Path\*.js", +# or "+process Folder\Path\*.htm". +# +#+process jsl-test.js diff --git a/tst/change.test.js b/tst/change.test.js index 83af510..b2ec8be 100644 --- a/tst/change.test.js +++ b/tst/change.test.js @@ -52,7 +52,7 @@ test('new with args', function(t) { test('GH-31 (multiple attributes per Change)', function(t) { try { - var change = new Change({ + new Change({ operation: 'replace', modification: { cn: 'foo', From 950b11695f851b768ba7f20e38ed30882513977a Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Tue, 24 Jan 2012 09:44:29 -0800 Subject: [PATCH 16/24] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 35aa42d..0a9f4d8 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "ldapjs", "homepage": "http://ldapjs.org", "description": "LDAP client and server APIs", - "version": "0.4.6", + "version": "0.4.7", "repository": { "type": "git", "url": "git://github.com/mcavage/node-ldapjs.git" From b47b208e5d86c33708a09bc2e25bded9978be4f1 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Mon, 30 Jan 2012 08:45:01 -0800 Subject: [PATCH 17/24] GH-55 Client emits connect event multiple times --- lib/client.js | 4 +--- tst/laundry.test.js | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/client.js b/lib/client.js index 22831cd..e550bce 100644 --- a/lib/client.js +++ b/lib/client.js @@ -198,11 +198,9 @@ Client.prototype.connect = function(callback) { self.connection.end(); } - self.emit('connect'); return callback(); }); - self.emit('connect'); return callback(); }); @@ -854,7 +852,7 @@ Client.prototype._newConnection = function() { c.ldap.connected = true; c.ldap.id += c.fd ? (':' + c.fd) : ''; - c.emit('connect', true); + c.emit('connect', c.ldap.id); }); c.setKeepAlive = function(enable, delay) { return c.socket.setKeepAlive(enable, delay); diff --git a/tst/laundry.test.js b/tst/laundry.test.js index 4b6401b..6843bcb 100644 --- a/tst/laundry.test.js +++ b/tst/laundry.test.js @@ -52,6 +52,10 @@ test('setup', function(t) { t.end(); }); + server.bind('cn=root', function(req, res, next) { + res.end(); + return next(); + }); server.search(SUFFIX, function(req, res, next) { var entry = { dn: 'cn=foo, ' + SUFFIX, @@ -106,6 +110,26 @@ test('GH-49 Client errors on bad attributes', function(t) { }); +test('GH-55 Client emits connect multiple times', function(t) { + var c = ldap.createClient({ + socketPath: SOCKET + }); + + var count = 0; + c.on('connect', function(socket) { + t.ok(socket); + count++; + }); + c.bind('cn=root', 'secret', function(err, res) { + t.ifError(err); + c.unbind(function() { + t.equal(count, 1); + t.end(); + }); + }); +}); + + test('shutdown', function(t) { client.unbind(function() { server.on('close', function() { From 4df59978cebab899c88ab4feb184cc0da025d577 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Tue, 14 Feb 2012 21:32:10 -0800 Subject: [PATCH 18/24] Stop nuking node_modules on make clean (breaks npm rebuild) --- Makefile | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 318c674..d369e3b 100644 --- a/Makefile +++ b/Makefile @@ -82,4 +82,4 @@ test: dep lint $(NPM) test clean: - @rm -fr ${DOCPKGDIR} node_modules *.log *.tar.gz + @rm -fr ${DOCPKGDIR} *.log *.tar.gz diff --git a/package.json b/package.json index 0a9f4d8..3a85702 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "ldapjs", "homepage": "http://ldapjs.org", "description": "LDAP client and server APIs", - "version": "0.4.7", + "version": "0.4.8", "repository": { "type": "git", "url": "git://github.com/mcavage/node-ldapjs.git" From afeb354eac523ffff1fe1c8f62947cde90a5bec5 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 18 Feb 2012 08:15:52 +0000 Subject: [PATCH 19/24] Initial setup for 0.5 (use eng.git layout) --- .dir-locals.el | 6 + .gitignore | 2 +- .gitmodules | 9 + Makefile | 120 ++--- Makefile.deps | 46 ++ deps/javascriptlint | 1 + deps/jsstyle | 1 + deps/restdown | 1 + lib/attribute.js | 44 +- lib/change.js | 35 +- lib/client.js | 220 ++++----- lib/controls/control.js | 18 +- .../entry_change_notification_control.js | 8 +- lib/controls/index.js | 1 + lib/controls/persistent_search_control.js | 8 +- lib/dn.js | 48 +- lib/dtrace.js | 10 +- lib/errors/index.js | 22 +- lib/filters/and_filter.js | 23 +- lib/filters/approx_filter.js | 18 +- lib/filters/equality_filter.js | 20 +- lib/filters/ext_filter.js | 26 +- lib/filters/filter.js | 10 +- lib/filters/ge_filter.js | 20 +- lib/filters/index.js | 50 +- lib/filters/le_filter.js | 20 +- lib/filters/not_filter.js | 12 +- lib/filters/or_filter.js | 23 +- lib/filters/presence_filter.js | 16 +- lib/filters/substr_filter.js | 24 +- lib/index.js | 18 +- lib/log_stub.js | 36 +- lib/messages/abandon_request.js | 16 +- lib/messages/abandon_response.js | 8 +- lib/messages/add_request.js | 46 +- lib/messages/add_response.js | 2 +- lib/messages/bind_request.js | 12 +- lib/messages/bind_response.js | 3 +- lib/messages/compare_request.js | 16 +- lib/messages/compare_response.js | 6 +- lib/messages/del_request.js | 12 +- lib/messages/del_response.js | 2 +- lib/messages/ext_request.js | 28 +- lib/messages/ext_response.js | 24 +- lib/messages/message.js | 20 +- lib/messages/moddn_request.js | 14 +- lib/messages/moddn_response.js | 2 +- lib/messages/modify_request.js | 19 +- lib/messages/modify_response.js | 2 +- lib/messages/parser.js | 14 +- lib/messages/result.js | 26 +- lib/messages/search_entry.js | 47 +- lib/messages/search_reference.js | 29 +- lib/messages/search_request.js | 24 +- lib/messages/search_response.js | 26 +- lib/messages/unbind_request.js | 24 +- lib/messages/unbind_response.js | 10 +- lib/schema/add_handler.js | 115 ----- lib/schema/index.js | 22 - lib/schema/mod_handler.js | 59 --- lib/schema/parser.js | 437 ------------------ lib/schema/search_handler.js | 87 ---- lib/schema/transform.js | 139 ------ lib/server.js | 170 ++++--- lib/url.js | 4 +- package.json | 14 +- {tst => test}/attribute.test.js | 10 +- {tst => test}/change.test.js | 17 +- {tst => test}/client.test.js | 174 +++---- {tst => test}/controls/control.test.js | 10 +- .../entry_change_notification_control_test.js | 8 +- .../persistent_search_control.test.js | 20 +- {tst => test}/dn.test.js | 36 +- {tst => test}/filters/and.test.js | 12 +- {tst => test}/filters/approx.test.js | 16 +- {tst => test}/filters/eq.test.js | 16 +- {tst => test}/filters/ext.test.js | 19 +- {tst => test}/filters/ge.test.js | 16 +- {tst => test}/filters/le.test.js | 16 +- {tst => test}/filters/not.test.js | 12 +- {tst => test}/filters/or.test.js | 12 +- {tst => test}/filters/parse.test.js | 18 +- {tst => test}/filters/presence.test.js | 12 +- {tst => test}/filters/substr.test.js | 16 +- {tst => test}/laundry.test.js | 34 +- {tst => test}/messages/add_request.test.js | 12 +- {tst => test}/messages/add_response.test.js | 10 +- {tst => test}/messages/bind_request.test.js | 10 +- {tst => test}/messages/bind_response.test.js | 10 +- .../messages/compare_request.test.js | 10 +- .../messages/compare_response.test.js | 10 +- {tst => test}/messages/del_request.test.js | 10 +- {tst => test}/messages/del_response.test.js | 10 +- {tst => test}/messages/ext_request.test.js | 10 +- {tst => test}/messages/ext_response.test.js | 10 +- {tst => test}/messages/moddn_request.test.js | 10 +- {tst => test}/messages/moddn_response.test.js | 10 +- {tst => test}/messages/modify_request.test.js | 10 +- .../messages/modify_response.test.js | 10 +- {tst => test}/messages/search_entry.test.js | 10 +- {tst => test}/messages/search_request.test.js | 10 +- .../messages/search_response.test.js | 10 +- {tst => test}/messages/unbind_request.test.js | 10 +- {tst => test}/url.test.js | 11 +- tools/{jsl.conf => jsl.node.conf} | 144 +++--- tools/jsstyle.conf | 4 + 106 files changed, 1180 insertions(+), 2030 deletions(-) create mode 100644 .dir-locals.el create mode 100644 .gitmodules create mode 100644 Makefile.deps create mode 160000 deps/javascriptlint create mode 160000 deps/jsstyle create mode 160000 deps/restdown delete mode 100644 lib/schema/add_handler.js delete mode 100644 lib/schema/index.js delete mode 100644 lib/schema/mod_handler.js delete mode 100644 lib/schema/parser.js delete mode 100644 lib/schema/search_handler.js delete mode 100644 lib/schema/transform.js rename {tst => test}/attribute.test.js (89%) rename {tst => test}/change.test.js (88%) rename {tst => test}/client.test.js (70%) rename {tst => test}/controls/control.test.js (87%) rename {tst => test}/controls/entry_change_notification_control_test.js (93%) rename {tst => test}/controls/persistent_search_control.test.js (86%) rename {tst => test}/dn.test.js (77%) rename {tst => test}/filters/and.test.js (87%) rename {tst => test}/filters/approx.test.js (85%) rename {tst => test}/filters/eq.test.js (85%) rename {tst => test}/filters/ext.test.js (84%) rename {tst => test}/filters/ge.test.js (85%) rename {tst => test}/filters/le.test.js (85%) rename {tst => test}/filters/not.test.js (84%) rename {tst => test}/filters/or.test.js (86%) rename {tst => test}/filters/parse.test.js (82%) rename {tst => test}/filters/presence.test.js (83%) rename {tst => test}/filters/substr.test.js (88%) rename {tst => test}/laundry.test.js (78%) rename {tst => test}/messages/add_request.test.js (94%) rename {tst => test}/messages/add_response.test.js (88%) rename {tst => test}/messages/bind_request.test.js (90%) rename {tst => test}/messages/bind_response.test.js (88%) rename {tst => test}/messages/compare_request.test.js (90%) rename {tst => test}/messages/compare_response.test.js (88%) rename {tst => test}/messages/del_request.test.js (87%) rename {tst => test}/messages/del_response.test.js (88%) rename {tst => test}/messages/ext_request.test.js (88%) rename {tst => test}/messages/ext_response.test.js (91%) rename {tst => test}/messages/moddn_request.test.js (90%) rename {tst => test}/messages/moddn_response.test.js (88%) rename {tst => test}/messages/modify_request.test.js (93%) rename {tst => test}/messages/modify_response.test.js (88%) rename {tst => test}/messages/search_entry.test.js (94%) rename {tst => test}/messages/search_request.test.js (94%) rename {tst => test}/messages/search_response.test.js (88%) rename {tst => test}/messages/unbind_request.test.js (82%) rename {tst => test}/url.test.js (86%) rename tools/{jsl.conf => jsl.node.conf} (68%) mode change 100755 => 100644 create mode 100644 tools/jsstyle.conf diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..7f37d53 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,6 @@ +((nil . ((indent-tabs-mode . nil) + (tab-width . 8) + (fill-column . 80))) + (js-mode . ((js-indent-level . 2) + (indent-tabs-mode . nil) + ))) diff --git a/.gitignore b/.gitignore index 6b08590..085ef65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ +build node_modules *.log *.ldif *.tar* -docs/pkg diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8ec36e0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "deps/javascriptlint"] + path = deps/javascriptlint + url = https://github.com/davepacheco/javascriptlint +[submodule "deps/jsstyle"] + path = deps/jsstyle + url = https://github.com/davepacheco/jsstyle +[submodule "deps/restdown"] + path = deps/restdown + url = https://github.com/trentm/restdown diff --git a/Makefile b/Makefile index d369e3b..f9f3ee4 100644 --- a/Makefile +++ b/Makefile @@ -1,85 +1,49 @@ +# +# Copyright (c) 2012, Joyent, Inc. All rights reserved. +# +# Makefile: basic Makefile for template API service +# +# This Makefile is a template for new repos. It contains only repo-specific +# logic and uses included makefiles to supply common targets (javascriptlint, +# jsstyle, restdown, etc.), which are used by other repos as well. You may well +# need to rewrite most of this file, but you shouldn't need to touch the +# included makefiles. +# +# If you find yourself adding support for new targets that could be useful for +# other projects too, you should add these to the original versions of the +# included Makefiles (in eng.git) so that other teams can use them too. +# -ifeq ($(VERSION), "") - @echo "Use gmake" -endif +# +# Tools +# +NPM := npm +TAP := ./node_modules/.bin/tap +# +# Files +# +DOC_FILES = client.md \ + dn.md \ + errors.md \ + examples.md \ + filters.md -DOCPKGDIR = ./docs/pkg -HAVE_GJSLINT := $(shell which gjslint >/dev/null && echo yes || echo no) -LINT = ./node_modules/.javascriptlint/build/install/jsl --conf ./tools/jsl.conf -NAME=ldapjs -RESTDOWN_VERSION=1.2.13 -SRC := $(shell pwd) -TAR = tar -UNAME := $(shell uname) -ifeq ($(UNAME), SunOS) - TAR = gtar -endif -NPM := npm_config_tar=$(TAR) npm +JS_FILES := $(shell find lib test -name '*.js') +JSL_CONF_NODE = tools/jsl.node.conf +JSL_FILES_NODE = $(JS_FILES) +JSSTYLE_FILES = $(JS_FILES) +JSSTYLE_FLAGS = -f tools/jsstyle.conf -RESTDOWN = ./node_modules/.restdown/bin/restdown \ - -b ./docs/branding \ - -m ${DOCPKGDIR} \ - -D mediaroot=media - -.PHONY: dep lint test doc clean all install - -all:: test doc - -node_modules/.ldapjs.npm.installed: +# Repo-specific targets +# +.PHONY: all +all: $(NPM) install - if [[ ! -d node_modules/.restdown ]]; then \ - git clone git://github.com/trentm/restdown.git node_modules/.restdown; \ - else \ - (cd node_modules/.restdown && git fetch origin); \ - fi - if [[ ! -d node_modules/.javascriptlint ]]; then \ - git clone https://github.com/davepacheco/javascriptlint node_modules/.javascriptlint; \ - else \ - (cd node_modules/.javascriptlint && git fetch origin); \ - fi +.PHONY: test +test: $(TAP) + $(TAP) test/*.test.js - @(cd ./node_modules/.restdown && git checkout $(RESTDOWN_VERSION)) - @(cd ./node_modules/.javascriptlint && $(MAKE) install) - @touch ./node_modules/.ldapjs.npm.installed - -dep: ./node_modules/.ldapjs.npm.installed -install: dep - -gjslint: - gjslint --nojsdoc -r lib -r tst - -ifeq ($(HAVE_GJSLINT), yes) -lint: install gjslint - ${LINT} --recurse lib/*.js -else -lint: install - @echo "* * *" - @echo "* Warning: Cannot lint with gjslint. Install it from:" - @echo "* http://code.google.com/closure/utilities/docs/linter_howto.html" - @echo "* * *" - ${LINT} --recurse lib/*.js -endif - -doc: dep - @rm -rf ${DOCPKGDIR} - @mkdir -p ${DOCPKGDIR} - ${RESTDOWN} ./docs/client.md - ${RESTDOWN} ./docs/dn.md - ${RESTDOWN} ./docs/errors.md - ${RESTDOWN} ./docs/examples.md - ${RESTDOWN} ./docs/filters.md - ${RESTDOWN} ./docs/guide.md - ${RESTDOWN} ./docs/index.md - ${RESTDOWN} ./docs/server.md - rm docs/*.json - mv docs/*.html ${DOCPKGDIR} - (cd ${DOCPKGDIR} && $(TAR) -czf ${SRC}/${NAME}-docs-`git log -1 --pretty='format:%h'`.tar.gz *) - - -test: dep lint - $(NPM) test - -clean: - @rm -fr ${DOCPKGDIR} *.log *.tar.gz +include ./Makefile.deps +include ./Makefile.targ diff --git a/Makefile.deps b/Makefile.deps new file mode 100644 index 0000000..48b4a8d --- /dev/null +++ b/Makefile.deps @@ -0,0 +1,46 @@ +# +# Copyright (c) 2012, Joyent, Inc. All rights reserved. +# +# Makefile.deps: Makefile for including common tools as dependencies +# + +# +# javascriptlint +# +JSL_SCRIPT = deps/javascriptlint/build/install/jsl +JSL = python $(JSL_SCRIPT) + +$(JSL_SCRIPT): | deps/javascriptlint/.git + cd deps/javascriptlint && make install + +deps/javascriptlint/.git: + git submodule update --init deps/javascriptlint + +# +# jsstyle +# +JSSTYLE_SCRIPT = deps/jsstyle/jsstyle +JSSTYLE = $(JSSTYLE_SCRIPT) + +deps/jsstyle/jsstyle: + git submodule update --init deps/jsstyle + +# +# restdown +# +RESTDOWN = python deps/restdown/bin/restdown + +$(RESTDOWN): | deps/restdown/.git + +deps/restdown/.git: + git submodule update --init deps/restdown + +# +# The restdown submodule should be updated before we build "docs". +# +docs: $(RESTDOWN) + +# +# JSL and JSSTYLE must be around before we build "check". +# +check: $(JSL_SCRIPT) $(JSSTYLE) diff --git a/deps/javascriptlint b/deps/javascriptlint new file mode 160000 index 0000000..5693fd3 --- /dev/null +++ b/deps/javascriptlint @@ -0,0 +1 @@ +Subproject commit 5693fd3ce6f31f66f85bfde275ab64e609ea04d0 diff --git a/deps/jsstyle b/deps/jsstyle new file mode 160000 index 0000000..ab8f1fc --- /dev/null +++ b/deps/jsstyle @@ -0,0 +1 @@ +Subproject commit ab8f1fc8d90db8484bbed8a526ff40add5aa1c15 diff --git a/deps/restdown b/deps/restdown new file mode 160000 index 0000000..14131f6 --- /dev/null +++ b/deps/restdown @@ -0,0 +1 @@ +Subproject commit 14131f6b33bf45a04b4c66e388d0ce1f3e5b55ef diff --git a/lib/attribute.js b/lib/attribute.js index 5c5a7bd..d819b81 100644 --- a/lib/attribute.js +++ b/lib/attribute.js @@ -12,9 +12,9 @@ var Protocol = require('./protocol'); function Attribute(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); - if (options.type && typeof(options.type) !== 'string') + if (options.type && typeof (options.type) !== 'string') throw new TypeError('options.type must be a string'); } else { options = {}; @@ -25,10 +25,11 @@ function Attribute(options) { this.type = options.type || ''; this._vals = []; - this.__defineGetter__('vals', function() { + this.__defineGetter__('vals', function () { var _vals = []; - self._vals.forEach(function(v) { + self._vals.forEach(function (v) { + /* JSSTYLED */ if (/;binary$/.test(self.type)) { _vals.push(v.toString('base64')); } else { @@ -39,9 +40,9 @@ function Attribute(options) { return _vals; }); - this.__defineSetter__('vals', function(vals) { + this.__defineSetter__('vals', function (vals) { if (Array.isArray(vals)) { - vals.forEach(function(v) { + vals.forEach(function (v) { self.addValue(v); }); } else { @@ -49,11 +50,11 @@ function Attribute(options) { } }); - this.__defineGetter__('buffers', function() { + this.__defineGetter__('buffers', function () { return self._vals; }); - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: self.type, vals: self.vals @@ -67,11 +68,12 @@ function Attribute(options) { module.exports = Attribute; -Attribute.prototype.addValue = function(val) { +Attribute.prototype.addValue = function (val) { if (Buffer.isBuffer(val)) { this._vals.push(val); } else { var encoding = 'utf8'; + /* JSSTYLED */ if (/;binary$/.test(this.type)) encoding = 'base64'; this._vals.push(new Buffer(val + '', encoding)); @@ -79,7 +81,8 @@ Attribute.prototype.addValue = function(val) { }; -Attribute.compare = function(a, b) { +/* BEGIN JSSTYLED */ +Attribute.compare = function compare(a, b) { if (!(a instanceof Attribute) || !(b instanceof Attribute)) throw new TypeError('can only compare Attributes'); @@ -95,9 +98,10 @@ Attribute.compare = function(a, b) { return 0; }; +/* END JSSTYLED */ -Attribute.prototype.parse = function(ber) { +Attribute.prototype.parse = function (ber) { assert.ok(ber); ber.readSequence(); @@ -115,14 +119,14 @@ Attribute.prototype.parse = function(ber) { }; -Attribute.prototype.toBer = function(ber) { +Attribute.prototype.toBer = function (ber) { assert.ok(ber); ber.startSequence(); ber.writeString(this.type); ber.startSequence(Protocol.LBER_SET); if (this._vals.length) { - this._vals.forEach(function(b) { + this._vals.forEach(function (b) { ber.writeByte(asn1.Ber.OctetString); ber.writeLength(b.length); for (var i = 0; i < b.length; i++) @@ -137,26 +141,28 @@ Attribute.prototype.toBer = function(ber) { return ber; }; -Attribute.toBer = function(attr, ber) { +Attribute.toBer = function (attr, ber) { return Attribute.prototype.toBer.call(attr, ber); }; -Attribute.isAttribute = function(attr) { +/* BEGIN JSSTYLED */ +Attribute.isAttribute = function (attr) { if (!attr) return false; - if (typeof(attr) !== 'object') return false; + if (typeof (attr) !== 'object') return false; if (attr instanceof Attribute) return true; - if (!attr.type || typeof(attr.type) !== 'string') return false; + if (!attr.type || typeof (attr.type) !== 'string') return false; if (!attr.vals || !Array.isArray(attr.vals)) return false; for (var i = 0; i < attr.vals.length; i++) { - if (typeof(attr.vals[i]) !== 'string' && !Buffer.isBuffer(attr.vals[i])) + if (typeof (attr.vals[i]) !== 'string' && !Buffer.isBuffer(attr.vals[i])) return false; } return true; }; +/* END JSSTLYED */ -Attribute.prototype.toString = function() { +Attribute.prototype.toString = function () { return JSON.stringify(this.json); }; diff --git a/lib/change.js b/lib/change.js index b765e35..511483d 100644 --- a/lib/change.js +++ b/lib/change.js @@ -11,16 +11,18 @@ var Protocol = require('./protocol'); function Change(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); - if (options.operation && typeof(options.operation) !== 'string') + if (options.operation && typeof (options.operation) !== 'string') throw new TypeError('options.operation must be a string'); } else { options = {}; } var self = this; - this.__defineGetter__('operation', function() { + this._modification = false; + + this.__defineGetter__('operation', function () { switch (self._operation) { case 0x00: return 'add'; case 0x01: return 'delete'; @@ -29,8 +31,8 @@ function Change(options) { throw new Error('0x' + self._operation.toString(16) + ' is invalid'); } }); - this.__defineSetter__('operation', function(val) { - if (typeof(val) !== 'string') + this.__defineSetter__('operation', function (val) { + if (typeof (val) !== 'string') throw new TypeError('operation must be a string'); switch (val.toLowerCase()) { @@ -47,10 +49,11 @@ function Change(options) { throw new Error('Invalid operation type: 0x' + val.toString(16)); } }); - this.__defineGetter__('modification', function() { + this.__defineGetter__('modification', function () { return self._modification; }); - this.__defineSetter__('modification', function(attr) { + + this.__defineSetter__('modification', function (attr) { if (Attribute.isAttribute(attr)) { self._modification = attr; return; @@ -59,10 +62,10 @@ function Change(options) { if (keys.length > 1) throw new Error('Only one attribute per Change allowed'); - keys.forEach(function(k) { + keys.forEach(function (k) { var _attr = new Attribute({type: k}); if (Array.isArray(attr[k])) { - attr[k].forEach(function(v) { + attr[k].forEach(function (v) { _attr.addValue(v.toString()); }); } else { @@ -71,7 +74,7 @@ function Change(options) { self._modification = _attr; }); }); - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { operation: self.operation, modification: self._modification ? self._modification.json : {} @@ -84,18 +87,20 @@ function Change(options) { module.exports = Change; -Change.compare = function(a, b) { +Change.compare = function (a, b) { if (!(a instanceof Change) || !(b instanceof Change)) throw new TypeError('can only compare Changes'); - if (a.operation < b.operation) return -1; - if (a.operation > b.operation) return 1; + if (a.operation < b.operation) + return -1; + if (a.operation > b.operation) + return 1; return Attribute.compare(a.modification, b.modification); }; -Change.prototype.parse = function(ber) { +Change.prototype.parse = function (ber) { assert.ok(ber); ber.readSequence(); @@ -107,7 +112,7 @@ Change.prototype.parse = function(ber) { }; -Change.prototype.toBer = function(ber) { +Change.prototype.toBer = function (ber) { assert.ok(ber); ber.startSequence(); diff --git a/lib/client.js b/lib/client.js index e550bce..173c4d6 100644 --- a/lib/client.js +++ b/lib/client.js @@ -53,8 +53,11 @@ var MAX_MSGID = Math.pow(2, 31) - 1; function xor() { var b = false; for (var i = 0; i < arguments.length; i++) { - if (arguments[i] && !b) b = true; - else if (arguments[i] && b) return false; + if (arguments[i] && !b) { + b = true; + } else if (arguments[i] && b) { + return false; + } } return b; } @@ -62,7 +65,7 @@ function xor() { function validateControls(controls) { if (Array.isArray(controls)) { - controls.forEach(function(c) { + controls.forEach(function (c) { if (!(c instanceof Control)) throw new TypeError('controls must be [Control]'); }); @@ -103,13 +106,13 @@ util.inherits(ConnectionError, errors.LDAPError); * @throws {TypeError} on bad input. */ function Client(options) { - if (!options || typeof(options) !== 'object') + if (!options || typeof (options) !== 'object') throw new TypeError('options (object) required'); - if (options.url && typeof(options.url) !== 'string') + if (options.url && typeof (options.url) !== 'string') throw new TypeError('options.url (string) required'); - if (options.socketPath && typeof(options.socketPath) !== 'string') + if (options.socketPath && typeof (options.socketPath) !== 'string') throw new TypeError('options.socketPath must be a string'); - if (options.log4js && typeof(options.log4js) !== 'object') + if (options.log4js && typeof (options.log4js) !== 'object') throw new TypeError('options.log4s must be an object'); if (!xor(options.url, options.socketPath)) @@ -132,19 +135,19 @@ function Client(options) { socketPath: options.socketPath || undefined }; this.log4js = options.log4js || logStub; - this.reconnect = (typeof(options.reconnect) === 'number' ? + this.reconnect = (typeof (options.reconnect) === 'number' ? options.reconnect : 1000); this.shutdown = false; this.timeout = options.timeout || false; - this.__defineGetter__('log', function() { + this.__defineGetter__('log', function () { if (!self._log) self._log = self.log4js.getLogger('Client'); return self._log; }); - return this.connect(function() {}); + return this.connect(function () {}); } util.inherits(Client, EventEmitter); module.exports = Client; @@ -156,14 +159,14 @@ module.exports = Client; * * @param {Function} callback invoked when `connect()` is done. */ -Client.prototype.connect = function(callback) { +Client.prototype.connect = function (callback) { if (this.connection) return callback(); var self = this; var timer = false; if (this.connectTimeout) { - timer = setTimeout(function() { + timer = setTimeout(function () { if (self.connection) self.connection.destroy(); @@ -178,21 +181,24 @@ Client.prototype.connect = function(callback) { function reconnect() { self.connection = null; - if (self.reconnect) - setTimeout(function() { self.connect(function() {}); }, self.reconnect); + if (self.reconnect) { + setTimeout(function () { + self.connect(function () {}); + }, self.reconnect); + } } - self.connection.on('close', function(had_err) { + self.connection.on('close', function (had_err) { self.emit('close', had_err); reconnect(); }); - self.connection.on('connect', function() { + self.connection.on('connect', function () { if (timer) clearTimeout(timer); if (self._bindDN && self._credentials) - return self.bind(self._bindDN, self._credentials, function(err) { + return self.bind(self._bindDN, self._credentials, function (err) { if (err) { self.log.error('Unable to bind(on(\'connect\')): %s', err.stack); self.connection.end(); @@ -218,23 +224,23 @@ Client.prototype.connect = function(callback) { * @param {Socket} conn don't use this. Internal only (reconnects). * @throws {TypeError} on invalid input. */ -Client.prototype.bind = function(name, credentials, controls, callback, conn) { - if (typeof(name) !== 'string' && !(name instanceof dn.DN)) +Client.prototype.bind = function (name, credentials, controls, callback, conn) { + if (typeof (name) !== 'string' && !(name instanceof dn.DN)) throw new TypeError('name (string) required'); - if (typeof(credentials) !== 'string') + if (typeof (credentials) !== 'string') throw new TypeError('credentials (string) required'); - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); var self = this; - this.connect(function() { + this.connect(function () { var req = new BindRequest({ name: name || '', authentication: 'Simple', @@ -242,7 +248,7 @@ Client.prototype.bind = function(name, credentials, controls, callback, conn) { controls: controls }); - return self._send(req, [errors.LDAP_SUCCESS], function(err, res) { + return self._send(req, [errors.LDAP_SUCCESS], function (err, res) { if (!err) { // In case we need to reconnect later self._bindDN = name; self._credentials = credentials; @@ -265,16 +271,16 @@ Client.prototype.bind = function(name, credentials, controls, callback, conn) { * @param {Function} callback of the form f(err). * @throws {TypeError} on invalid input. */ -Client.prototype.abandon = function(messageID, controls, callback) { - if (typeof(messageID) !== 'number') +Client.prototype.abandon = function (messageID, controls, callback) { + if (typeof (messageID) !== 'number') throw new TypeError('messageID (number) required'); - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); var req = new AbandonRequest({ @@ -299,22 +305,22 @@ Client.prototype.abandon = function(messageID, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.add = function(name, entry, controls, callback) { - if (typeof(name) !== 'string') +Client.prototype.add = function (name, entry, controls, callback) { + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); - if (typeof(entry) !== 'object') + if (typeof (entry) !== 'object') throw new TypeError('entry (object) required'); - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); if (Array.isArray(entry)) { - entry.forEach(function(a) { + entry.forEach(function (a) { if (!Attribute.isAttribute(a)) throw new TypeError('entry must be an Array of Attributes'); }); @@ -322,10 +328,10 @@ Client.prototype.add = function(name, entry, controls, callback) { var save = entry; entry = []; - Object.keys(save).forEach(function(k) { + Object.keys(save).forEach(function (k) { var attr = new Attribute({type: k}); if (Array.isArray(save[k])) { - save[k].forEach(function(v) { + save[k].forEach(function (v) { attr.addValue(v.toString()); }); } else { @@ -355,20 +361,20 @@ Client.prototype.add = function(name, entry, controls, callback) { * @param {Function} callback of the form f(err, boolean, res). * @throws {TypeError} on invalid input. */ -Client.prototype.compare = function(name, attr, value, controls, callback) { - if (typeof(name) !== 'string') +Client.prototype.compare = function (name, attr, value, controls, callback) { + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); - if (typeof(attr) !== 'string') + if (typeof (attr) !== 'string') throw new TypeError('attribute (string) required'); - if (typeof(value) !== 'string') + if (typeof (value) !== 'string') throw new TypeError('value (string) required'); - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); var req = new CompareRequest({ @@ -399,16 +405,16 @@ Client.prototype.compare = function(name, attr, value, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.del = function(name, controls, callback) { - if (typeof(name) !== 'string') +Client.prototype.del = function (name, controls, callback) { + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); var req = new DeleteRequest({ @@ -433,23 +439,23 @@ Client.prototype.del = function(name, controls, callback) { * @param {Function} callback of the form f(err, value, res). * @throws {TypeError} on invalid input. */ -Client.prototype.exop = function(name, value, controls, callback) { - if (typeof(name) !== 'string') +Client.prototype.exop = function (name, value, controls, callback) { + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); - if (typeof(value) === 'function') { + if (typeof (value) === 'function') { callback = value; controls = []; value = ''; } - if (typeof(value) !== 'string') + if (typeof (value) !== 'string') throw new TypeError('value (string) required'); - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); var req = new ExtendedRequest({ @@ -478,10 +484,10 @@ Client.prototype.exop = function(name, value, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.modify = function(name, change, controls, callback) { - if (typeof(name) !== 'string') +Client.prototype.modify = function (name, change, controls, callback) { + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); - if (typeof(change) !== 'object') + if (typeof (change) !== 'object') throw new TypeError('change (Change) required'); var changes = []; @@ -489,10 +495,10 @@ Client.prototype.modify = function(name, change, controls, callback) { function changeFromObject(change) { if (!change.operation && !change.type) throw new Error('change.operation required'); - if (typeof(change.modification) !== 'object') + if (typeof (change.modification) !== 'object') throw new Error('change.modification (object) required'); - Object.keys(change.modification).forEach(function(k) { + Object.keys(change.modification).forEach(function (k) { var mod = {}; mod[k] = change.modification[k]; changes.push(new Change({ @@ -505,7 +511,7 @@ Client.prototype.modify = function(name, change, controls, callback) { if (change instanceof Change) { changes.push(change); } else if (Array.isArray(change)) { - change.forEach(function(c) { + change.forEach(function (c) { if (c instanceof Change) { changes.push(c); } else { @@ -516,13 +522,13 @@ Client.prototype.modify = function(name, change, controls, callback) { changeFromObject(change); } - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); var req = new ModifyRequest({ @@ -549,18 +555,18 @@ Client.prototype.modify = function(name, change, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.modifyDN = function(name, newName, controls, callback) { - if (typeof(name) !== 'string') +Client.prototype.modifyDN = function (name, newName, controls, callback) { + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); - if (typeof(newName) !== 'string') + if (typeof (newName) !== 'string') throw new TypeError('newName (string) required'); - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); var DN = dn.parse(name); @@ -606,24 +612,24 @@ Client.prototype.modifyDN = function(name, newName, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.search = function(base, options, controls, callback) { - if (typeof(base) !== 'string' && !(base instanceof dn.DN)) +Client.prototype.search = function (base, options, controls, callback) { + if (typeof (base) !== 'string' && !(base instanceof dn.DN)) throw new TypeError('base (string) required'); if (Array.isArray(options) || (options instanceof Control)) { controls = options; options = {}; - } else if (typeof(options) === 'function') { + } else if (typeof (options) === 'function') { callback = options; controls = []; options = { filter: new PresenceFilter({attribute: 'objectclass'}) }; - } else if (typeof(options) === 'string') { + } else if (typeof (options) === 'string') { options = {filter: filters.parseString(options)}; - } else if (typeof(options) !== 'object') { + } else if (typeof (options) !== 'object') { throw new TypeError('options (object) required'); } - if (typeof(options.filter) === 'string') { + if (typeof (options.filter) === 'string') { options.filter = filters.parseString(options.filter); } else if (!options.filter) { options.filter = new PresenceFilter({attribute: 'objectclass'}); @@ -631,26 +637,26 @@ Client.prototype.search = function(base, options, controls, callback) { throw new TypeError('options.filter (Filter) required'); } - if (typeof(controls) === 'function') { + if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } - if (typeof(callback) !== 'function') + if (typeof (callback) !== 'function') throw new TypeError('callback (function) required'); if (options.attributes) { - if (Array.isArray(options.attributes)) { - // noop - } else if (typeof(options.attributes) === 'string') { - options.attributes = [options.attributes]; - } else { - throw new TypeError('options.attributes must be an Array of Strings'); + if (!Array.isArray(options.attributes)) { + if (typeof (options.attributes) === 'string') { + options.attributes = [options.attributes]; + } else { + throw new TypeError('options.attributes must be an Array of Strings'); + } } } var req = new SearchRequest({ - baseObject: typeof(base) === 'string' ? dn.parse(base) : base, + baseObject: typeof (base) === 'string' ? dn.parse(base) : base, scope: options.scope || 'base', filter: options.filter, derefAliases: Protocol.NEVER_DEREF_ALIASES, @@ -698,11 +704,11 @@ Client.prototype.search = function(base, options, controls, callback) { * @param {Function} callback of the form f(err). * @throws {TypeError} if you pass in callback as not a function. */ -Client.prototype.unbind = function(callback) { - if (callback && typeof(callback) !== 'function') +Client.prototype.unbind = function (callback) { + if (callback && typeof (callback) !== 'function') throw new TypeError('callback must be a function'); if (!callback) - callback = function() { self.log.trace('disconnected'); }; + callback = function () { self.log.trace('disconnected'); }; var self = this; this.reconnect = false; @@ -718,7 +724,7 @@ Client.prototype.unbind = function(callback) { -Client.prototype._send = function(message, expect, callback, connection) { +Client.prototype._send = function (message, expect, callback, connection) { assert.ok(message); assert.ok(expect); assert.ok(callback); @@ -734,7 +740,7 @@ Client.prototype._send = function(message, expect, callback, connection) { err = err || new ConnectionError('no connection'); - if (typeof(callback) === 'function') { + if (typeof (callback) === 'function') { callback(err); } else { callback.emit('error', err); @@ -750,7 +756,7 @@ Client.prototype._send = function(message, expect, callback, connection) { // Now set up the callback in the messages table message.messageID = conn.ldap.nextMessageID; if (expect !== 'abandon') { - conn.ldap.messages[message.messageID] = function(res) { + conn.ldap.messages[message.messageID] = function (res) { if (timer) clearTimeout(timer); @@ -764,13 +770,13 @@ Client.prototype._send = function(message, expect, callback, connection) { if (expect.indexOf(res.status) === -1) { err = errors.getError(res); - if (typeof(callback) === 'function') + if (typeof (callback) === 'function') return callback(err); return callback.emit('error', err); } - if (typeof(callback) === 'function') + if (typeof (callback) === 'function') return callback(null, res); callback.emit('end', res); @@ -783,7 +789,7 @@ Client.prototype._send = function(message, expect, callback, connection) { callback.emit('searchReference', res); } else if (res instanceof Error) { - if (typeof(callback) === 'function') + if (typeof (callback) === 'function') return callback(res); assert.ok(callback instanceof EventEmitter); @@ -792,7 +798,7 @@ Client.prototype._send = function(message, expect, callback, connection) { delete conn.ldap.messages[message.messageID]; err = new errors.ProtocolError(res.type); - if (typeof(callback) === 'function') + if (typeof (callback) === 'function') return callback(err); callback.emit('error', err); @@ -804,7 +810,7 @@ Client.prototype._send = function(message, expect, callback, connection) { // If there's a user specified timeout, pick that up if (this.timeout) { - timer = setTimeout(function() { + timer = setTimeout(function () { self.emit('timeout', message); if (conn.ldap.messages[message.messageID]) conn.ldap.messages[message.messageID](new LDAPResult({ @@ -819,11 +825,11 @@ Client.prototype._send = function(message, expect, callback, connection) { // will never be a response var _writeCb = null; if (expect === 'abandon') { - _writeCb = function() { + _writeCb = function () { return callback(); }; } else if (expect === 'unbind') { - _writeCb = function() { + _writeCb = function () { conn.unbindMessageID = message.id; conn.end(); }; @@ -839,14 +845,14 @@ Client.prototype._send = function(message, expect, callback, connection) { }; -Client.prototype._newConnection = function() { +Client.prototype._newConnection = function () { var c; var connectOpts = this.connectOptions; var log = this.log; var self = this; if (this.secure) { - c = tls.connect(connectOpts.port, connectOpts.host, function() { + c = tls.connect(connectOpts.port, connectOpts.host, function () { if (log.isTraceEnabled()) log.trace('%s connect event', c.ldap.id); @@ -854,7 +860,7 @@ Client.prototype._newConnection = function() { c.ldap.id += c.fd ? (':' + c.fd) : ''; c.emit('connect', c.ldap.id); }); - c.setKeepAlive = function(enable, delay) { + c.setKeepAlive = function (enable, delay) { return c.socket.setKeepAlive(enable, delay); }; } else { @@ -873,13 +879,13 @@ Client.prototype._newConnection = function() { messages: {} }; - c.ldap.__defineGetter__('nextMessageID', function() { + c.ldap.__defineGetter__('nextMessageID', function () { if (++c.ldap.messageID >= MAX_MSGID) c.ldap.messageID = 1; return c.ldap.messageID; }); - c.on('connect', function() { + c.on('connect', function () { if (log.isTraceEnabled()) log.trace('%s connect event', c.ldap.id); @@ -888,18 +894,18 @@ Client.prototype._newConnection = function() { self.emit('connect', c.ldap.id); }); - c.on('end', function() { + c.on('end', function () { if (log.isTraceEnabled()) log.trace('%s end event', c.ldap.id); c.end(); }); - c.on('close', function(had_err) { + c.on('close', function (had_err) { if (log.isTraceEnabled()) log.trace('%s close event had_err=%s', c.ldap.id, had_err ? 'yes' : 'no'); - Object.keys(c.ldap.messages).forEach(function(msgid) { + Object.keys(c.ldap.messages).forEach(function (msgid) { var err; if (c.unbindMessageID !== parseInt(msgid, 10)) { err = new ConnectionError(c.ldap.id + ' closed'); @@ -910,7 +916,7 @@ Client.prototype._newConnection = function() { err.status = 'unbind'; } - if (typeof(c.ldap.messages[msgid]) === 'function') { + if (typeof (c.ldap.messages[msgid]) === 'function') { var callback = c.ldap.messages[msgid]; delete c.ldap.messages[msgid]; return callback(err); @@ -926,7 +932,7 @@ Client.prototype._newConnection = function() { }); }); - c.on('error', function(err) { + c.on('error', function (err) { if (log.isTraceEnabled()) log.trace('%s error event=%s', c.ldap.id, err ? err.stack : '?'); @@ -936,7 +942,7 @@ Client.prototype._newConnection = function() { c.end(); }); - c.on('timeout', function() { + c.on('timeout', function () { if (log.isTraceEnabled()) log.trace('%s timeout event=%s', c.ldap.id); @@ -944,7 +950,7 @@ Client.prototype._newConnection = function() { c.end(); }); - c.on('data', function(data) { + c.on('data', function (data) { if (log.isTraceEnabled()) log.trace('%s data event: %s', c.ldap.id, util.inspect(data)); @@ -952,7 +958,7 @@ Client.prototype._newConnection = function() { }); // The "router" - c.parser.on('message', function(message) { + c.parser.on('message', function (message) { message.connection = c; var callback = c.ldap.messages[message.messageID]; @@ -964,7 +970,7 @@ Client.prototype._newConnection = function() { return callback(message); }); - c.parser.on('error', function(err) { + c.parser.on('error', function (err) { if (log.isTraceEnabled()) log.trace('%s error event=%s', c.ldap.id, err ? err.stack : '?'); diff --git a/lib/controls/control.js b/lib/controls/control.js index d1f084a..e5d723d 100644 --- a/lib/controls/control.js +++ b/lib/controls/control.js @@ -19,14 +19,14 @@ var Ber = asn1.Ber; function Control(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); - if (options.type && typeof(options.type) !== 'string') + if (options.type && typeof (options.type) !== 'string') throw new TypeError('options.type must be a string'); if (options.criticality !== undefined && - typeof(options.criticality) !== 'boolean') + typeof (options.criticality) !== 'boolean') throw new TypeError('options.criticality must be a boolean'); - if (options.value && typeof(options.value) !== 'string') + if (options.value && typeof (options.value) !== 'string') throw new TypeError('options.value must be a string'); } else { options = {}; @@ -37,25 +37,25 @@ function Control(options) { this.value = options.value || null; var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { var obj = { controlType: self.type, criticality: self.criticality, controlValue: self.value }; - return (typeof(self._json) === 'function' ? self._json(obj) : obj); + return (typeof (self._json) === 'function' ? self._json(obj) : obj); }); } module.exports = Control; -Control.prototype.toBer = function(ber) { +Control.prototype.toBer = function (ber) { assert.ok(ber); ber.startSequence(); ber.writeString(this.type || ''); ber.writeBoolean(this.criticality); - if (typeof(this._toBer) === 'function') { + if (typeof (this._toBer) === 'function') { this._toBer(ber); } else { if (this.value) @@ -67,6 +67,6 @@ Control.prototype.toBer = function(ber) { }; -Control.prototype.toString = function() { +Control.prototype.toString = function () { return this.json; }; diff --git a/lib/controls/entry_change_notification_control.js b/lib/controls/entry_change_notification_control.js index 4893021..4b1205a 100644 --- a/lib/controls/entry_change_notification_control.js +++ b/lib/controls/entry_change_notification_control.js @@ -24,7 +24,7 @@ function EntryChangeNotificationControl(options) { if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); - } else if (typeof(options.value) === 'object') { + } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); @@ -34,7 +34,7 @@ function EntryChangeNotificationControl(options) { Control.call(this, options); var self = this; - this.__defineGetter__('value', function() { + this.__defineGetter__('value', function () { return self._value || {}; }); } @@ -64,7 +64,7 @@ EntryChangeNotificationControl.prototype.parse = function parse(buffer) { }; -EntryChangeNotificationControl.prototype._toBer = function(ber) { +EntryChangeNotificationControl.prototype._toBer = function (ber) { assert.ok(ber); if (!this._value) @@ -83,7 +83,7 @@ EntryChangeNotificationControl.prototype._toBer = function(ber) { }; -EntryChangeNotificationControl.prototype._json = function(obj) { +EntryChangeNotificationControl.prototype._json = function (obj) { obj.controlValue = this.value; return obj; }; diff --git a/lib/controls/index.js b/lib/controls/index.js index d8715a2..a77b906 100644 --- a/lib/controls/index.js +++ b/lib/controls/index.js @@ -56,6 +56,7 @@ module.exports = { critical: critical, value: value ? value.toString('utf8') : null }); + break; } return control; diff --git a/lib/controls/persistent_search_control.js b/lib/controls/persistent_search_control.js index 47170bf..33f3471 100644 --- a/lib/controls/persistent_search_control.js +++ b/lib/controls/persistent_search_control.js @@ -26,7 +26,7 @@ function PersistentSearchControl(options) { if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); - } else if (typeof(options.value) === 'object') { + } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); @@ -36,7 +36,7 @@ function PersistentSearchControl(options) { Control.call(this, options); var self = this; - this.__defineGetter__('value', function() { + this.__defineGetter__('value', function () { return self._value || {}; }); } @@ -62,7 +62,7 @@ PersistentSearchControl.prototype.parse = function parse(buffer) { }; -PersistentSearchControl.prototype._toBer = function(ber) { +PersistentSearchControl.prototype._toBer = function (ber) { assert.ok(ber); if (!this._value) @@ -79,7 +79,7 @@ PersistentSearchControl.prototype._toBer = function(ber) { }; -PersistentSearchControl.prototype._json = function(obj) { +PersistentSearchControl.prototype._json = function (obj) { obj.controlValue = this.value; return obj; }; diff --git a/lib/dn.js b/lib/dn.js index 7ff9842..bee7199 100644 --- a/lib/dn.js +++ b/lib/dn.js @@ -25,18 +25,18 @@ function RDN(obj) { var self = this; if (obj) { - Object.keys(obj).forEach(function(k) { + Object.keys(obj).forEach(function (k) { self[k.toLowerCase()] = obj[k]; }); } } -RDN.prototype.toString = function() { +RDN.prototype.toString = function () { var self = this; var str = ''; - Object.keys(this).forEach(function(k) { + Object.keys(this).forEach(function (k) { if (str.length) str += '+'; @@ -48,7 +48,7 @@ RDN.prototype.toString = function() { // Thank you OpenJDK! function parse(name) { - if (typeof(name) !== 'string') + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); var cur = 0; @@ -190,30 +190,30 @@ function parse(name) { function DN(rdns) { if (!Array.isArray(rdns)) throw new TypeError('rdns ([object]) required'); - rdns.forEach(function(rdn) { - if (typeof(rdn) !== 'object') + rdns.forEach(function (rdn) { + if (typeof (rdn) !== 'object') throw new TypeError('rdns ([object]) required'); }); this.rdns = rdns.slice(); - this.__defineGetter__('length', function() { + this.__defineGetter__('length', function () { return this.rdns.length; }); } -DN.prototype.toString = function() { +DN.prototype.toString = function () { var _dn = []; - this.rdns.forEach(function(rdn) { + this.rdns.forEach(function (rdn) { _dn.push(rdn.toString()); }); return _dn.join(', '); }; -DN.prototype.childOf = function(dn) { - if (typeof(dn) !== 'object') +DN.prototype.childOf = function (dn) { + if (typeof (dn) !== 'object') dn = parse(dn); if (this.rdns.length <= dn.rdns.length) @@ -239,8 +239,8 @@ DN.prototype.childOf = function(dn) { }; -DN.prototype.parentOf = function(dn) { - if (typeof(dn) !== 'object') +DN.prototype.parentOf = function (dn) { + if (typeof (dn) !== 'object') dn = parse(dn); if (!this.rdns.length || this.rdns.length >= dn.rdns.length) @@ -266,8 +266,8 @@ DN.prototype.parentOf = function(dn) { }; -DN.prototype.equals = function(dn) { - if (typeof(dn) !== 'object') +DN.prototype.equals = function (dn) { + if (typeof (dn) !== 'object') dn = parse(dn); if (this.rdns.length !== dn.rdns.length) @@ -296,7 +296,7 @@ DN.prototype.equals = function(dn) { }; -DN.prototype.parent = function() { +DN.prototype.parent = function () { if (this.rdns.length > 1) { var save = this.rdns.shift(); var dn = new DN(this.rdns); @@ -308,37 +308,37 @@ DN.prototype.parent = function() { }; -DN.prototype.clone = function() { +DN.prototype.clone = function () { return new DN(this.rdns); }; -DN.prototype.reverse = function() { +DN.prototype.reverse = function () { this.rdns.reverse(); return this; }; -DN.prototype.pop = function() { +DN.prototype.pop = function () { return this.rdns.pop(); }; -DN.prototype.push = function(rdn) { - if (typeof(rdn) !== 'object') +DN.prototype.push = function (rdn) { + if (typeof (rdn) !== 'object') throw new TypeError('rdn (RDN) required'); return this.rdns.push(rdn); }; -DN.prototype.shift = function() { +DN.prototype.shift = function () { return this.rdns.shift(); }; -DN.prototype.unshift = function(rdn) { - if (typeof(rdn) !== 'object') +DN.prototype.unshift = function (rdn) { + if (typeof (rdn) !== 'object') throw new TypeError('rdn (RDN) required'); return this.rdns.unshift(rdn); diff --git a/lib/dtrace.js b/lib/dtrace.js index 3b1728a..42d6abe 100644 --- a/lib/dtrace.js +++ b/lib/dtrace.js @@ -10,7 +10,8 @@ var SERVER_PROVIDER; var DTRACE_ID = 0; var MAX_INT = 4294967295; -/* Args: +/* + * Args: * server-*-start: * 0 -> id * 1 -> remoteIP @@ -76,11 +77,11 @@ var SERVER_PROBES = { ///--- API -module.exports = function() { +module.exports = function () { if (!SERVER_PROVIDER) { SERVER_PROVIDER = dtrace.createDTraceProvider('ldapjs'); - Object.keys(SERVER_PROBES).forEach(function(p) { + Object.keys(SERVER_PROBES).forEach(function (p) { var args = SERVER_PROBES[p].splice(0); args.unshift(p); @@ -89,7 +90,7 @@ module.exports = function() { SERVER_PROVIDER.enable(); - SERVER_PROVIDER._nextId = function() { + SERVER_PROVIDER._nextId = function () { if (DTRACE_ID === MAX_INT) DTRACE_ID = 0; @@ -99,4 +100,3 @@ module.exports = function() { return SERVER_PROVIDER; }(); - diff --git a/lib/errors/index.js b/lib/errors/index.js index e826787..33315a0 100644 --- a/lib/errors/index.js +++ b/lib/errors/index.js @@ -59,16 +59,16 @@ function LDAPError(errorName, errorCode, msg, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); - this.__defineGetter__('dn', function() { + this.__defineGetter__('dn', function () { return (dn ? (dn.toString() || '') : ''); }); - this.__defineGetter__('code', function() { + this.__defineGetter__('code', function () { return errorCode; }); - this.__defineGetter__('name', function() { + this.__defineGetter__('name', function () { return errorName; }); - this.__defineGetter__('message', function() { + this.__defineGetter__('message', function () { return msg || errorName; }); } @@ -82,7 +82,7 @@ util.inherits(LDAPError, Error); module.exports = {}; module.exports.LDAPError = LDAPError; -Object.keys(CODES).forEach(function(code) { +Object.keys(CODES).forEach(function (code) { module.exports[code] = CODES[code]; if (code === 'LDAP_SUCCESS') return; @@ -102,14 +102,14 @@ Object.keys(CODES).forEach(function(code) { // At this point LDAP_OPERATIONS_ERROR is now OperationsError in $err // and 'Operations Error' in $msg - module.exports[err] = function(message, dn, caller) { + module.exports[err] = function (message, dn, caller) { LDAPError.call(this, err, CODES[code], message || msg, dn || null, caller || module.exports[err]); - } + }; module.exports[err].constructor = module.exports[err]; util.inherits(module.exports[err], LDAPError); @@ -120,7 +120,7 @@ Object.keys(CODES).forEach(function(code) { }); -module.exports.getError = function(res) { +module.exports.getError = function (res) { if (!(res instanceof LDAPResult)) throw new TypeError('res (LDAPResult) required'); @@ -132,10 +132,10 @@ module.exports.getError = function(res) { }; -module.exports.getMessage = function(code) { - if (typeof(code) !== 'number') +module.exports.getMessage = function (code) { + if (typeof (code) !== 'number') throw new TypeError('code (number) required'); - var errObj = ERRORS[res.status]; + var errObj = ERRORS[code]; return (errObj && errObj.message ? errObj.message : ''); }; diff --git a/lib/filters/and_filter.js b/lib/filters/and_filter.js index 2d3a5c0..f72524c 100644 --- a/lib/filters/and_filter.js +++ b/lib/filters/and_filter.js @@ -12,7 +12,7 @@ var Protocol = require('../protocol'); ///--- API function AndFilter(options) { - if (typeof(options) === 'object') { + if (typeof (options) === 'object') { if (!options.filters || !Array.isArray(options.filters)) throw new TypeError('options.filters ([Filter]) required'); this.filters = options.filters.slice(); @@ -27,7 +27,7 @@ function AndFilter(options) { this.filters = []; var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'And', filters: self.filters || [] @@ -38,9 +38,9 @@ util.inherits(AndFilter, Filter); module.exports = AndFilter; -AndFilter.prototype.toString = function() { +AndFilter.prototype.toString = function () { var str = '(&'; - this.filters.forEach(function(f) { + this.filters.forEach(function (f) { str += f.toString(); }); str += ')'; @@ -49,32 +49,33 @@ AndFilter.prototype.toString = function() { }; -AndFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +AndFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); var matches = this.filters.length ? true : false; - for (var i = 0; i < this.filters.length; i++) + for (var i = 0; i < this.filters.length; i++) { if (!this.filters[i].matches(target)) return false; + } return matches; }; -AndFilter.prototype.addFilter = function(filter) { - if (!filter || typeof(filter) !== 'object') +AndFilter.prototype.addFilter = function (filter) { + if (!filter || typeof (filter) !== 'object') throw new TypeError('filter (object) required'); this.filters.push(filter); }; -AndFilter.prototype._toBer = function(ber) { +AndFilter.prototype._toBer = function (ber) { assert.ok(ber); - this.filters.forEach(function(f) { + this.filters.forEach(function (f) { ber = f.toBer(ber); }); diff --git a/lib/filters/approx_filter.js b/lib/filters/approx_filter.js index 21a432d..e654b83 100644 --- a/lib/filters/approx_filter.js +++ b/lib/filters/approx_filter.js @@ -12,10 +12,10 @@ var Protocol = require('../protocol'); ///--- API function ApproximateFilter(options) { - if (typeof(options) === 'object') { - if (!options.attribute || typeof(options.attribute) !== 'string') + if (typeof (options) === 'object') { + if (!options.attribute || typeof (options.attribute) !== 'string') throw new TypeError('options.attribute (string) required'); - if (!options.value || typeof(options.value) !== 'string') + if (!options.value || typeof (options.value) !== 'string') throw new TypeError('options.value (string) required'); this.attribute = options.attribute; this.value = options.value; @@ -26,7 +26,7 @@ function ApproximateFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'ApproximateMatch', attribute: self.attribute || undefined, @@ -38,13 +38,13 @@ util.inherits(ApproximateFilter, Filter); module.exports = ApproximateFilter; -ApproximateFilter.prototype.toString = function() { +ApproximateFilter.prototype.toString = function () { return '(' + this.attribute + '~=' + this.value + ')'; }; -ApproximateFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +ApproximateFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); var matches = false; @@ -61,7 +61,7 @@ ApproximateFilter.prototype.matches = function(target) { }; -ApproximateFilter.prototype.parse = function(ber) { +ApproximateFilter.prototype.parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); @@ -71,7 +71,7 @@ ApproximateFilter.prototype.parse = function(ber) { }; -ApproximateFilter.prototype._toBer = function(ber) { +ApproximateFilter.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.attribute); diff --git a/lib/filters/equality_filter.js b/lib/filters/equality_filter.js index 5a1fa7e..4bd9bf7 100644 --- a/lib/filters/equality_filter.js +++ b/lib/filters/equality_filter.js @@ -12,10 +12,10 @@ var Protocol = require('../protocol'); ///--- API function EqualityFilter(options) { - if (typeof(options) === 'object') { - if (!options.attribute || typeof(options.attribute) !== 'string') + if (typeof (options) === 'object') { + if (!options.attribute || typeof (options.attribute) !== 'string') throw new TypeError('options.attribute (string) required'); - if (!options.value || typeof(options.value) !== 'string') + if (!options.value || typeof (options.value) !== 'string') throw new TypeError('options.value (string) required'); this.attribute = options.attribute; this.value = options.value; @@ -26,7 +26,7 @@ function EqualityFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'EqualityMatch', attribute: self.attribute || undefined, @@ -38,19 +38,19 @@ util.inherits(EqualityFilter, Filter); module.exports = EqualityFilter; -EqualityFilter.prototype.toString = function() { +EqualityFilter.prototype.toString = function () { return '(' + this.attribute + '=' + this.value + ')'; }; -EqualityFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +EqualityFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); if (target.hasOwnProperty(this.attribute)) { var value = this.value; return Filter.multi_test( - function(v) { return value === v; }, + function (v) { return value === v; }, target[this.attribute]); } @@ -58,7 +58,7 @@ EqualityFilter.prototype.matches = function(target) { }; -EqualityFilter.prototype.parse = function(ber) { +EqualityFilter.prototype.parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); @@ -71,7 +71,7 @@ EqualityFilter.prototype.parse = function(ber) { }; -EqualityFilter.prototype._toBer = function(ber) { +EqualityFilter.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.attribute); diff --git a/lib/filters/ext_filter.js b/lib/filters/ext_filter.js index 8f84031..339fbda 100644 --- a/lib/filters/ext_filter.js +++ b/lib/filters/ext_filter.js @@ -12,12 +12,12 @@ var Protocol = require('../protocol'); ///--- API function ExtensibleFilter(options) { - if (typeof(options) === 'object') { - if (options.rule && typeof(options.rule) !== 'string') + if (typeof (options) === 'object') { + if (options.rule && typeof (options.rule) !== 'string') throw new TypeError('options.rule must be a string'); - if (options.matchType && typeof(options.matchType) !== 'string') + if (options.matchType && typeof (options.matchType) !== 'string') throw new TypeError('options.type must be a string'); - if (options.value && typeof(options.value) !== 'string') + if (options.value && typeof (options.value) !== 'string') throw new TypeError('options.value (string) required'); } else { options = {}; @@ -31,7 +31,7 @@ function ExtensibleFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'ExtensibleMatch', matchRule: self.rule, @@ -40,10 +40,10 @@ function ExtensibleFilter(options) { dnAttributes: self.dnAttributes }; }); - this.__defineGetter__('matchingRule', function() { + this.__defineGetter__('matchingRule', function () { return self.rule; }); - this.__defineGetter__('matchValue', function() { + this.__defineGetter__('matchValue', function () { return self.value; }); } @@ -51,7 +51,7 @@ util.inherits(ExtensibleFilter, Filter); module.exports = ExtensibleFilter; -ExtensibleFilter.prototype.toString = function() { +ExtensibleFilter.prototype.toString = function () { var str = '('; if (this.matchType) @@ -78,8 +78,8 @@ ExtensibleFilter.prototype.toString = function() { * @param {Object} target the target object. * @return {Boolean} false always. */ -ExtensibleFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +ExtensibleFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); if (this.dnAttribute) @@ -90,7 +90,7 @@ ExtensibleFilter.prototype.matches = function(target) { var self = this; if (this.matchType && target.hasOwnProperty(this.matchType)) { - return Filter.multi_test(function(v) { + return Filter.multi_test(function (v) { if (self.rule === '2.5.13.2') return self.value.toLowerCase() === v.toLowerCase(); @@ -102,7 +102,7 @@ ExtensibleFilter.prototype.matches = function(target) { }; -ExtensibleFilter.prototype.parse = function(ber) { +ExtensibleFilter.prototype.parse = function (ber) { var end = ber.offset + ber.length; while (ber.offset < end) { var tag = ber.peek(); @@ -128,7 +128,7 @@ ExtensibleFilter.prototype.parse = function(ber) { }; -ExtensibleFilter.prototype._toBer = function(ber) { +ExtensibleFilter.prototype._toBer = function (ber) { assert.ok(ber); if (this.rule) diff --git a/lib/filters/filter.js b/lib/filters/filter.js index 5b428dc..1956c14 100644 --- a/lib/filters/filter.js +++ b/lib/filters/filter.js @@ -18,15 +18,15 @@ var BerWriter = asn1.BerWriter; ///--- API function Filter(options) { - if (!options || typeof(options) !== 'object') + if (!options || typeof (options) !== 'object') throw new TypeError('options (object) required'); - if (typeof(options.type) !== 'number') + if (typeof (options.type) !== 'number') throw new TypeError('options.type (number) required'); this._type = options.type; var self = this; - this.__defineGetter__('type', function() { + this.__defineGetter__('type', function () { switch (self._type) { case Protocol.FILTER_AND: return 'and'; case Protocol.FILTER_OR: return 'or'; @@ -47,7 +47,7 @@ function Filter(options) { module.exports = Filter; -Filter.prototype.toBer = function(ber) { +Filter.prototype.toBer = function (ber) { if (!ber || !(ber instanceof BerWriter)) throw new TypeError('ber (BerWriter) required'); @@ -61,7 +61,7 @@ Filter.prototype.toBer = function(ber) { /* * Test a rule against one or more values. */ -Filter.multi_test = function(rule, value) { +Filter.multi_test = function (rule, value) { if (Array.isArray(value)) { var response = false; for (var i = 0; i < value.length; i++) { diff --git a/lib/filters/ge_filter.js b/lib/filters/ge_filter.js index a2aa7d4..c25163d 100644 --- a/lib/filters/ge_filter.js +++ b/lib/filters/ge_filter.js @@ -12,10 +12,10 @@ var Protocol = require('../protocol'); ///--- API function GreaterThanEqualsFilter(options) { - if (typeof(options) === 'object') { - if (!options.attribute || typeof(options.attribute) !== 'string') + if (typeof (options) === 'object') { + if (!options.attribute || typeof (options.attribute) !== 'string') throw new TypeError('options.attribute (string) required'); - if (!options.value || typeof(options.value) !== 'string') + if (!options.value || typeof (options.value) !== 'string') throw new TypeError('options.value (string) required'); this.attribute = options.attribute; this.value = options.value; @@ -27,7 +27,7 @@ function GreaterThanEqualsFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'GreaterThanEqualsMatch', attribute: self.attribute || undefined, @@ -39,19 +39,19 @@ util.inherits(GreaterThanEqualsFilter, Filter); module.exports = GreaterThanEqualsFilter; -GreaterThanEqualsFilter.prototype.toString = function() { +GreaterThanEqualsFilter.prototype.toString = function () { return '(' + this.attribute + '>=' + this.value + ')'; }; -GreaterThanEqualsFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +GreaterThanEqualsFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); if (target.hasOwnProperty(this.attribute)) { var value = this.value; return Filter.multi_test( - function(v) { return value <= v; }, + function (v) { return value <= v; }, target[this.attribute]); } @@ -59,7 +59,7 @@ GreaterThanEqualsFilter.prototype.matches = function(target) { }; -GreaterThanEqualsFilter.prototype.parse = function(ber) { +GreaterThanEqualsFilter.prototype.parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); @@ -69,7 +69,7 @@ GreaterThanEqualsFilter.prototype.parse = function(ber) { }; -GreaterThanEqualsFilter.prototype._toBer = function(ber) { +GreaterThanEqualsFilter.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.attribute); diff --git a/lib/filters/index.js b/lib/filters/index.js index 2d4379f..fba58a6 100644 --- a/lib/filters/index.js +++ b/lib/filters/index.js @@ -60,8 +60,16 @@ function matchParens(str, openParenIndex) { // the filter tree is an intermediary step between the incoming expression and // the outgoing Filter Class structure. function _buildFilterTree(expr) { + var c; + var child; + var clean = false; + var endParen; + var esc = false; + var i = 0; var tree = {}; var split; + var substrNdx = 0; + var val = ''; if (expr.length === 0) return tree; @@ -85,13 +93,10 @@ function _buildFilterTree(expr) { } if (tree.op != 'expr') { - var child; - var i = 0; tree.children = []; // logical operators are k-ary, so we go until our expression string runs // out (at least for this recursion level) - var endParen; while (expr.length !== 0) { endParen = matchParens(expr); if (endParen == expr.length - 1) { @@ -107,29 +112,23 @@ function _buildFilterTree(expr) { } else { //else its some sort of non-logical expression, parse and return as such var operatorStr = ''; - var valueOffset = 0; tree.name = ''; tree.value = ''; if (expr.indexOf('~=') !== -1) { operatorStr = '~='; tree.tag = 'approxMatch'; - valueOffset = 2; } else if (expr.indexOf('>=') !== -1) { operatorStr = '>='; tree.tag = 'greaterOrEqual'; - valueOffset = 2; } else if (expr.indexOf('<=') !== -1) { operatorStr = '<='; tree.tag = 'lessOrEqual'; - valueOffset = 2; } else if (expr.indexOf(':=') !== -1) { operatorStr = ':='; tree.tag = 'extensibleMatch'; - valueOffset = 2; } else if (expr.indexOf('=') !== -1) { operatorStr = '='; tree.tag = 'equalityMatch'; - valueOffset = 1; } else { tree.tag = 'present'; } @@ -138,7 +137,6 @@ function _buildFilterTree(expr) { tree.name = expr; } else { // pull out lhs and rhs of equality operator - var clean = false; var splitAry = expr.split(operatorStr); tree.name = splitAry.shift(); tree.value = splitAry.join(operatorStr); @@ -149,17 +147,14 @@ function _buildFilterTree(expr) { if (tree.value.length === 0) { tree.tag = 'present'; } else { - var substrNdx = 0; - var substr = false; - var esc = false; // Effectively a hand-rolled .shift() to support \* sequences clean = true; split = []; substrNdx = 0; split[substrNdx] = ''; - for (var i = 0; i < tree.value.length; i++) { - var c = tree.value[i]; + for (i = 0; i < tree.value.length; i++) { + c = tree.value[i]; if (esc) { split[substrNdx] += c; esc = false; @@ -227,10 +222,9 @@ function _buildFilterTree(expr) { // Cleanup any escape sequences if (!clean) { - var val = ''; - var esc = false; - for (var i = 0; i < tree.value.length; i++) { - var c = tree.value[i]; + + for (i = 0; i < tree.value.length; i++) { + c = tree.value[i]; if (esc) { val += c; esc = false; @@ -250,7 +244,7 @@ function _buildFilterTree(expr) { function serializeTree(tree, filter) { if (tree === undefined || tree.length === 0) - return filter; + return; // if the current tree object is not an expression then its a logical // operator (ie an internal node in the tree) @@ -266,11 +260,13 @@ function serializeTree(tree, filter) { case 'not': current = new NotFilter(); break; + default: + break; } filter.addFilter(current || filter); if (current || tree.children.length) { - tree.children.forEach(function(child) { + tree.children.forEach(function (child) { serializeTree(child, current); }); } @@ -321,8 +317,11 @@ function serializeTree(tree, filter) { attribute: tree.name }); break; + default: + break; } - filter.addFilter(tmp); + if (tmp) + filter.addFilter(tmp); } } @@ -457,15 +456,15 @@ function _parse(ber) { module.exports = { - parse: function(ber) { + parse: function (ber) { if (!ber || !(ber instanceof BerReader)) throw new TypeError('ber (BerReader) required'); return _parse(ber); }, - parseString: function(filter) { - if (!filter || typeof(filter) !== 'string') + parseString: function (filter) { + if (!filter || typeof (filter) !== 'string') throw new TypeError('filter (string) required'); return _parseString(filter); @@ -483,4 +482,3 @@ module.exports = { SubstringFilter: SubstringFilter, Filter: Filter }; - diff --git a/lib/filters/le_filter.js b/lib/filters/le_filter.js index e90fa03..b5fd910 100644 --- a/lib/filters/le_filter.js +++ b/lib/filters/le_filter.js @@ -12,10 +12,10 @@ var Protocol = require('../protocol'); ///--- API function LessThanEqualsFilter(options) { - if (typeof(options) === 'object') { - if (!options.attribute || typeof(options.attribute) !== 'string') + if (typeof (options) === 'object') { + if (!options.attribute || typeof (options.attribute) !== 'string') throw new TypeError('options.attribute (string) required'); - if (!options.value || typeof(options.value) !== 'string') + if (!options.value || typeof (options.value) !== 'string') throw new TypeError('options.value (string) required'); this.attribute = options.attribute; this.value = options.value; @@ -27,7 +27,7 @@ function LessThanEqualsFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'LessThanEqualsMatch', attribute: self.attribute || undefined, @@ -39,19 +39,19 @@ util.inherits(LessThanEqualsFilter, Filter); module.exports = LessThanEqualsFilter; -LessThanEqualsFilter.prototype.toString = function() { +LessThanEqualsFilter.prototype.toString = function () { return '(' + this.attribute + '<=' + this.value + ')'; }; -LessThanEqualsFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +LessThanEqualsFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); if (target.hasOwnProperty(this.attribute)) { var value = this.value; return Filter.multi_test( - function(v) { return value >= v; }, + function (v) { return value >= v; }, target[this.attribute]); } @@ -59,7 +59,7 @@ LessThanEqualsFilter.prototype.matches = function(target) { }; -LessThanEqualsFilter.prototype.parse = function(ber) { +LessThanEqualsFilter.prototype.parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); @@ -69,7 +69,7 @@ LessThanEqualsFilter.prototype.parse = function(ber) { }; -LessThanEqualsFilter.prototype._toBer = function(ber) { +LessThanEqualsFilter.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.attribute); diff --git a/lib/filters/not_filter.js b/lib/filters/not_filter.js index a473a9a..f4b9038 100644 --- a/lib/filters/not_filter.js +++ b/lib/filters/not_filter.js @@ -12,7 +12,7 @@ var Protocol = require('../protocol'); ///--- API function NotFilter(options) { - if (typeof(options) === 'object') { + if (typeof (options) === 'object') { if (!options.filter || !(options.filter instanceof Filter)) throw new TypeError('options.filter (Filter) required'); @@ -25,7 +25,7 @@ function NotFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'Not', filter: self.filter @@ -36,23 +36,23 @@ util.inherits(NotFilter, Filter); module.exports = NotFilter; -NotFilter.prototype.addFilter = function(f) { +NotFilter.prototype.addFilter = function (f) { if (!(f instanceof Filter)) throw new TypeError('filter (Filter) required'); this.filter = f; }; -NotFilter.prototype.toString = function() { +NotFilter.prototype.toString = function () { return '(!' + this.filter.toString() + ')'; }; -NotFilter.prototype.matches = function(target) { +NotFilter.prototype.matches = function (target) { return !this.filter.matches(target); }; -NotFilter.prototype._toBer = function(ber) { +NotFilter.prototype._toBer = function (ber) { assert.ok(ber); return this.filter.toBer(ber); diff --git a/lib/filters/or_filter.js b/lib/filters/or_filter.js index b2b28ed..a9daa04 100644 --- a/lib/filters/or_filter.js +++ b/lib/filters/or_filter.js @@ -12,7 +12,7 @@ var Protocol = require('../protocol'); ///--- API function OrFilter(options) { - if (typeof(options) === 'object') { + if (typeof (options) === 'object') { if (!options.filters || !Array.isArray(options.filters)) throw new TypeError('options.filters ([Filter]) required'); this.filters = options.filters.slice(); @@ -27,7 +27,7 @@ function OrFilter(options) { this.filters = []; var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'Or', filters: self.filters || [] @@ -38,9 +38,9 @@ util.inherits(OrFilter, Filter); module.exports = OrFilter; -OrFilter.prototype.toString = function() { +OrFilter.prototype.toString = function () { var str = '(|'; - this.filters.forEach(function(f) { + this.filters.forEach(function (f) { str += f.toString(); }); str += ')'; @@ -49,30 +49,31 @@ OrFilter.prototype.toString = function() { }; -OrFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +OrFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); - for (var i = 0; i < this.filters.length; i++) + for (var i = 0; i < this.filters.length; i++) { if (this.filters[i].matches(target)) return true; + } return false; }; -OrFilter.prototype.addFilter = function(filter) { - if (!filter || typeof(filter) !== 'object') +OrFilter.prototype.addFilter = function (filter) { + if (!filter || typeof (filter) !== 'object') throw new TypeError('filter (object) required'); this.filters.push(filter); }; -OrFilter.prototype._toBer = function(ber) { +OrFilter.prototype._toBer = function (ber) { assert.ok(ber); - this.filters.forEach(function(f) { + this.filters.forEach(function (f) { ber = f.toBer(ber); }); diff --git a/lib/filters/presence_filter.js b/lib/filters/presence_filter.js index 9fccf90..8a57ca4 100644 --- a/lib/filters/presence_filter.js +++ b/lib/filters/presence_filter.js @@ -11,8 +11,8 @@ var Protocol = require('../protocol'); ///--- API function PresenceFilter(options) { - if (typeof(options) === 'object') { - if (!options.attribute || typeof(options.attribute) !== 'string') + if (typeof (options) === 'object') { + if (!options.attribute || typeof (options.attribute) !== 'string') throw new TypeError('options.attribute (string) required'); this.attribute = options.attribute; } else { @@ -22,7 +22,7 @@ function PresenceFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'PresenceMatch', attribute: self.attribute || undefined @@ -33,20 +33,20 @@ util.inherits(PresenceFilter, Filter); module.exports = PresenceFilter; -PresenceFilter.prototype.toString = function() { +PresenceFilter.prototype.toString = function () { return '(' + this.attribute + '=*)'; }; -PresenceFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +PresenceFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); return target.hasOwnProperty(this.attribute); }; -PresenceFilter.prototype.parse = function(ber) { +PresenceFilter.prototype.parse = function (ber) { assert.ok(ber); this.attribute = @@ -58,7 +58,7 @@ PresenceFilter.prototype.parse = function(ber) { }; -PresenceFilter.prototype._toBer = function(ber) { +PresenceFilter.prototype._toBer = function (ber) { assert.ok(ber); for (var i = 0; i < this.attribute.length; i++) diff --git a/lib/filters/substr_filter.js b/lib/filters/substr_filter.js index 64331d2..4c1c57c 100644 --- a/lib/filters/substr_filter.js +++ b/lib/filters/substr_filter.js @@ -12,8 +12,8 @@ var Protocol = require('../protocol'); ///--- API function SubstringFilter(options) { - if (typeof(options) === 'object') { - if (!options.attribute || typeof(options.attribute) !== 'string') + if (typeof (options) === 'object') { + if (!options.attribute || typeof (options.attribute) !== 'string') throw new TypeError('options.attribute (string) required'); this.attribute = options.attribute; this.initial = options.initial || null; @@ -30,7 +30,7 @@ function SubstringFilter(options) { Filter.call(this, options); var self = this; - this.__defineGetter__('json', function() { + this.__defineGetter__('json', function () { return { type: 'SubstringMatch', initial: self.initial || undefined, @@ -43,7 +43,7 @@ util.inherits(SubstringFilter, Filter); module.exports = SubstringFilter; -SubstringFilter.prototype.toString = function() { +SubstringFilter.prototype.toString = function () { var str = '(' + this.attribute + '='; if (this.initial) @@ -51,7 +51,7 @@ SubstringFilter.prototype.toString = function() { str += '*'; - this.any.forEach(function(s) { + this.any.forEach(function (s) { str += s + '*'; }); @@ -64,8 +64,8 @@ SubstringFilter.prototype.toString = function() { }; -SubstringFilter.prototype.matches = function(target) { - if (typeof(target) !== 'object') +SubstringFilter.prototype.matches = function (target) { + if (typeof (target) !== 'object') throw new TypeError('target (object) required'); if (target.hasOwnProperty(this.attribute)) { @@ -73,7 +73,7 @@ SubstringFilter.prototype.matches = function(target) { if (this.initial) re += '^' + this.initial + '.*'; - this.any.forEach(function(s) { + this.any.forEach(function (s) { re += s + '.*'; }); @@ -82,7 +82,7 @@ SubstringFilter.prototype.matches = function(target) { var matcher = new RegExp(re); return Filter.multi_test( - function(v) { return matcher.test(v); }, + function (v) { return matcher.test(v); }, target[this.attribute]); } @@ -90,7 +90,7 @@ SubstringFilter.prototype.matches = function(target) { }; -SubstringFilter.prototype.parse = function(ber) { +SubstringFilter.prototype.parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); @@ -125,7 +125,7 @@ SubstringFilter.prototype.parse = function(ber) { }; -SubstringFilter.prototype._toBer = function(ber) { +SubstringFilter.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.attribute); @@ -135,7 +135,7 @@ SubstringFilter.prototype._toBer = function(ber) { ber.writeString(this.initial, 0x80); if (this.any && this.any.length) - this.any.forEach(function(s) { + this.any.forEach(function (s) { ber.writeString(s, 0x81); }); diff --git a/lib/index.js b/lib/index.js index 630e179..d460259 100644 --- a/lib/index.js +++ b/lib/index.js @@ -13,7 +13,6 @@ var errors = require('./errors'); var filters = require('./filters'); var logStub = require('./log_stub'); var messages = require('./messages'); -var schema = require('./schema'); var url = require('./url'); @@ -21,7 +20,7 @@ var url = require('./url'); /// Hack a few things we need (i.e., "monkey patch" the prototype) if (!String.prototype.startsWith) { - String.prototype.startsWith = function(str) { + String.prototype.startsWith = function (str) { var re = new RegExp('^' + str); return re.test(this); }; @@ -29,7 +28,7 @@ if (!String.prototype.startsWith) { if (!String.prototype.endsWith) { - String.prototype.endsWith = function(str) { + String.prototype.endsWith = function (str) { var re = new RegExp(str + '$'); return re.test(this); }; @@ -42,15 +41,15 @@ if (!String.prototype.endsWith) { module.exports = { Client: Client, - createClient: function(options) { - if (typeof(options) !== 'object') + createClient: function (options) { + if (typeof (options) !== 'object') throw new TypeError('options (object) required'); return new Client(options); }, Server: Server, - createServer: function(options) { + createServer: function (options) { return new Server(options); }, @@ -67,12 +66,7 @@ module.exports = { log4js: logStub, parseURL: url.parse, - url: url, - - loadSchema: schema.load, - createSchemaAddHandler: schema.createAddHandler, - createSchemaModifyHandler: schema.createModifyHandler, - createSchemaSearchHandler: schema.createSearchHandler + url: url }; diff --git a/lib/log_stub.js b/lib/log_stub.js index 6579113..43d5d22 100644 --- a/lib/log_stub.js +++ b/lib/log_stub.js @@ -46,7 +46,7 @@ function format(level, name, args) { args = fmtArgs.concat(args); - var output = (FMT_STR + fmtStr).replace(/%[sdj]/g, function(match) { + var output = (FMT_STR + fmtStr).replace(/%[sdj]/g, function (match) { switch (match) { case '%s': return new String(args.shift()); case '%d': return new Number(args.shift()); @@ -67,61 +67,61 @@ function Log(name) { this.name = name; } -Log.prototype._write = function(level, args) { +Log.prototype._write = function (level, args) { var data = format(level, this.name, args); console.error(data); }; -Log.prototype.isTraceEnabled = function() { +Log.prototype.isTraceEnabled = function () { return (LEVELS.Trace >= LEVELS[level]); }; -Log.prototype.trace = function() { +Log.prototype.trace = function () { if (this.isTraceEnabled()) this._write('TRACE', Array.prototype.slice.call(arguments)); }; -Log.prototype.isDebugEnabled = function() { +Log.prototype.isDebugEnabled = function () { return (LEVELS.Debug >= LEVELS[level]); }; -Log.prototype.debug = function() { +Log.prototype.debug = function () { if (this.isDebugEnabled()) this._write('DEBUG', Array.prototype.slice.call(arguments)); }; -Log.prototype.isInfoEnabled = function() { +Log.prototype.isInfoEnabled = function () { return (LEVELS.Info >= LEVELS[level]); }; -Log.prototype.info = function() { +Log.prototype.info = function () { if (this.isInfoEnabled()) this._write('INFO', Array.prototype.slice.call(arguments)); }; -Log.prototype.isWarnEnabled = function() { +Log.prototype.isWarnEnabled = function () { return (LEVELS.Warn >= LEVELS[level]); }; -Log.prototype.warn = function() { +Log.prototype.warn = function () { if (this.isWarnEnabled()) this._write('WARN', Array.prototype.slice.call(arguments)); }; -Log.prototype.isErrorEnabled = function() { +Log.prototype.isErrorEnabled = function () { return (LEVELS.Error >= LEVELS[level]); }; -Log.prototype.error = function() { +Log.prototype.error = function () { if (this.isErrorEnabled()) this._write('ERROR', Array.prototype.slice.call(arguments)); }; -Log.prototype.isFatalEnabled = function() { +Log.prototype.isFatalEnabled = function () { return (LEVELS.Fatal >= LEVELS[level]); }; -Log.prototype.fatal = function() { +Log.prototype.fatal = function () { if (this.isFatalEnabled()) this._write('FATAL', Array.prototype.slice.call(arguments)); }; @@ -129,7 +129,7 @@ Log.prototype.fatal = function() { module.exports = { - setLevel: function(l) { + setLevel: function (l) { l = l.charAt(0).toUpperCase() + l.slice(1).toLowerCase(); if (LEVELS[l] !== undefined) level = l; @@ -137,14 +137,14 @@ module.exports = { return level; }, - getLogger: function(name) { - if (!name || typeof(name) !== 'string') + getLogger: function (name) { + if (!name || typeof (name) !== 'string') throw new TypeError('name (string) required'); return new Log(name); }, - setGlobalLogLevel: function(l) { + setGlobalLogLevel: function (l) { l = l.charAt(0).toUpperCase() + l.slice(1).toLowerCase(); if (LEVELS[l] !== undefined) level = l; diff --git a/lib/messages/abandon_request.js b/lib/messages/abandon_request.js index b044b2a..22637bd 100644 --- a/lib/messages/abandon_request.js +++ b/lib/messages/abandon_request.js @@ -22,9 +22,9 @@ var Ber = asn1.Ber; function AbandonRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); - if (options.abandonID && typeof(options.abandonID) !== 'number') + if (options.abandonID && typeof (options.abandonID) !== 'number') throw new TypeError('abandonID must be a number'); } else { options = {}; @@ -35,14 +35,13 @@ function AbandonRequest(options) { this.abandonID = options.abandonID || 0; - var self = this; - this.__defineGetter__('type', function() { return 'AbandonRequest'; }); + this.__defineGetter__('type', function () { return 'AbandonRequest'; }); } util.inherits(AbandonRequest, LDAPMessage); module.exports = AbandonRequest; -AbandonRequest.prototype._parse = function(ber, length) { +AbandonRequest.prototype._parse = function (ber, length) { assert.ok(ber); assert.ok(length); @@ -71,13 +70,13 @@ AbandonRequest.prototype._parse = function(ber, length) { }; -AbandonRequest.prototype._toBer = function(ber) { +AbandonRequest.prototype._toBer = function (ber) { assert.ok(ber); var i = this.abandonID; var sz = 4; - while ((((i & 0xff800000) == 0) || ((i & 0xff800000) == 0xff800000)) && + while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000)) && (sz > 1)) { sz--; i <<= 8; @@ -93,11 +92,10 @@ AbandonRequest.prototype._toBer = function(ber) { }; -AbandonRequest.prototype._json = function(j) { +AbandonRequest.prototype._json = function (j) { assert.ok(j); j.abandonID = this.abandonID; return j; }; - diff --git a/lib/messages/abandon_response.js b/lib/messages/abandon_response.js index c390bf5..874d5c7 100644 --- a/lib/messages/abandon_response.js +++ b/lib/messages/abandon_response.js @@ -13,20 +13,20 @@ var Protocol = require('../protocol'); function AbandonResponse(options) { if (!options) options = {}; - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); options.protocolOp = 0; LDAPMessage.call(this, options); - this.__defineGetter__('type', function() { return 'AbandonResponse'; }); + this.__defineGetter__('type', function () { return 'AbandonResponse'; }); } util.inherits(AbandonResponse, LDAPMessage); module.exports = AbandonResponse; -AbandonResponse.prototype.end = function(status) {}; +AbandonResponse.prototype.end = function (status) {}; -AbandonResponse.prototype._json = function(j) { +AbandonResponse.prototype._json = function (j) { return j; }; diff --git a/lib/messages/add_request.js b/lib/messages/add_request.js index b78b0a9..afed4b4 100644 --- a/lib/messages/add_request.js +++ b/lib/messages/add_request.js @@ -22,14 +22,14 @@ var Ber = asn1.Ber; function AddRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.entry && !(options.entry instanceof dn.DN)) throw new TypeError('options.entry must be a DN'); if (options.attributes) { if (!Array.isArray(options.attributes)) throw new TypeError('options.attributes must be [Attribute]'); - options.attributes.forEach(function(a) { + options.attributes.forEach(function (a) { if (!Attribute.isAttribute(a)) throw new TypeError('options.attributes must be [Attribute]'); }); @@ -45,14 +45,14 @@ function AddRequest(options) { this.attributes = options.attributes ? options.attributes.slice(0) : []; var self = this; - this.__defineGetter__('type', function() { return 'AddRequest'; }); - this.__defineGetter__('_dn', function() { return self.entry; }); + this.__defineGetter__('type', function () { return 'AddRequest'; }); + this.__defineGetter__('_dn', function () { return self.entry; }); } util.inherits(AddRequest, LDAPMessage); module.exports = AddRequest; -AddRequest.prototype._parse = function(ber) { +AddRequest.prototype._parse = function (ber) { assert.ok(ber); this.entry = dn.parse(ber.readString()); @@ -76,12 +76,12 @@ AddRequest.prototype._parse = function(ber) { }; -AddRequest.prototype._toBer = function(ber) { +AddRequest.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.entry.toString()); ber.startSequence(); - this.attributes.forEach(function(a) { + this.attributes.forEach(function (a) { a.toBer(ber); }); ber.endSequence(); @@ -90,13 +90,13 @@ AddRequest.prototype._toBer = function(ber) { }; -AddRequest.prototype._json = function(j) { +AddRequest.prototype._json = function (j) { assert.ok(j); j.entry = this.entry.toString(); j.attributes = []; - this.attributes.forEach(function(a) { + this.attributes.forEach(function (a) { j.attributes.push(a.json); }); @@ -104,45 +104,47 @@ AddRequest.prototype._json = function(j) { }; -AddRequest.prototype.indexOf = function(attr) { - if (!attr || typeof(attr) !== 'string') +AddRequest.prototype.indexOf = function (attr) { + if (!attr || typeof (attr) !== 'string') throw new TypeError('attr (string) required'); - for (var i = 0; i < this.attributes.length; i++) + for (var i = 0; i < this.attributes.length; i++) { if (this.attributes[i].type === attr) return i; + } return -1; }; -AddRequest.prototype.attributeNames = function() { +AddRequest.prototype.attributeNames = function () { var attrs = []; for (var i = 0; i < this.attributes.length; i++) - attrs.push[this.attributes[i].type.toLowerCase()]; + attrs.push(this.attributes[i].type.toLowerCase()); return attrs; }; -AddRequest.prototype.getAttribute = function(name) { - if (!name || typeof(name) !== 'string') +AddRequest.prototype.getAttribute = function (name) { + if (!name || typeof (name) !== 'string') throw new TypeError('attribute name (string) required'); name = name.toLowerCase(); - for (var i = 0; i < this.attributes.length; i++) + for (var i = 0; i < this.attributes.length; i++) { if (this.attributes[i].type === name) return this.attribute[i]; + } return null; }; -AddRequest.prototype.addAttribute = function(attr) { +AddRequest.prototype.addAttribute = function (attr) { if (!(attr instanceof Attribute)) - throw new TypeEroror('attribute (Attribute) required'); + throw new TypeError('attribute (Attribute) required'); return this.attributes.push(attr); }; @@ -163,7 +165,7 @@ AddRequest.prototype.addAttribute = function(attr) { * * @return {Object} that looks like the above. */ -AddRequest.prototype.toObject = function() { +AddRequest.prototype.toObject = function () { var self = this; var obj = { @@ -174,11 +176,11 @@ AddRequest.prototype.toObject = function() { if (!this.attributes || !this.attributes.length) return obj; - this.attributes.forEach(function(a) { + this.attributes.forEach(function (a) { if (!obj.attributes[a.type]) obj.attributes[a.type] = []; - a.vals.forEach(function(v) { + a.vals.forEach(function (v) { if (obj.attributes[a.type].indexOf(v) === -1) obj.attributes[a.type].push(v); }); diff --git a/lib/messages/add_response.js b/lib/messages/add_response.js index 7324f1a..b5ac773 100644 --- a/lib/messages/add_response.js +++ b/lib/messages/add_response.js @@ -11,7 +11,7 @@ var Protocol = require('../protocol'); function AddResponse(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; diff --git a/lib/messages/bind_request.js b/lib/messages/bind_request.js index e07862d..ab31434 100644 --- a/lib/messages/bind_request.js +++ b/lib/messages/bind_request.js @@ -24,7 +24,7 @@ var LDAP_BIND_SASL = 'sasl'; ///--- API function BindRequest(options) { - if (options && typeof(options) !== 'object') + if (options && typeof (options) !== 'object') throw new TypeError('options must be an object'); options = options || {}; @@ -38,14 +38,14 @@ function BindRequest(options) { this.credentials = options.credentials || ''; var self = this; - this.__defineGetter__('type', function() { return 'BindRequest'; }); - this.__defineGetter__('_dn', function() { return self.name; }); + this.__defineGetter__('type', function () { return 'BindRequest'; }); + this.__defineGetter__('_dn', function () { return self.name; }); } util.inherits(BindRequest, LDAPMessage); module.exports = BindRequest; -BindRequest.prototype._parse = function(ber) { +BindRequest.prototype._parse = function (ber) { assert.ok(ber); this.version = ber.readInt(); @@ -64,7 +64,7 @@ BindRequest.prototype._parse = function(ber) { }; -BindRequest.prototype._toBer = function(ber) { +BindRequest.prototype._toBer = function (ber) { assert.ok(ber); ber.writeInt(this.version); @@ -76,7 +76,7 @@ BindRequest.prototype._toBer = function(ber) { }; -BindRequest.prototype._json = function(j) { +BindRequest.prototype._json = function (j) { assert.ok(j); j.version = this.version; diff --git a/lib/messages/bind_response.js b/lib/messages/bind_response.js index 0f8f3ac..edb0a71 100644 --- a/lib/messages/bind_response.js +++ b/lib/messages/bind_response.js @@ -11,7 +11,7 @@ var Protocol = require('../protocol'); function BindResponse(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; @@ -22,4 +22,3 @@ function BindResponse(options) { } util.inherits(BindResponse, LDAPResult); module.exports = BindResponse; - diff --git a/lib/messages/compare_request.js b/lib/messages/compare_request.js index d6bffad..8c81253 100644 --- a/lib/messages/compare_request.js +++ b/lib/messages/compare_request.js @@ -15,13 +15,13 @@ var Protocol = require('../protocol'); function CompareRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.entry && !(options.entry instanceof dn.DN)) throw new TypeError('options.entry must be a DN'); - if (options.attribute && typeof(options.attribute) !== 'string') + if (options.attribute && typeof (options.attribute) !== 'string') throw new TypeError('options.attribute must be a string'); - if (options.value && typeof(options.value) !== 'string') + if (options.value && typeof (options.value) !== 'string') throw new TypeError('options.value must be a string'); } else { options = {}; @@ -35,8 +35,8 @@ function CompareRequest(options) { this.value = options.value || ''; var self = this; - this.__defineGetter__('type', function() { return 'CompareRequest'; }); - this.__defineGetter__('_dn', function() { + this.__defineGetter__('type', function () { return 'CompareRequest'; }); + this.__defineGetter__('_dn', function () { return self.entry ? self.entry.toString() : ''; }); } @@ -44,7 +44,7 @@ util.inherits(CompareRequest, LDAPMessage); module.exports = CompareRequest; -CompareRequest.prototype._parse = function(ber) { +CompareRequest.prototype._parse = function (ber) { assert.ok(ber); this.entry = dn.parse(ber.readString()); @@ -57,7 +57,7 @@ CompareRequest.prototype._parse = function(ber) { }; -CompareRequest.prototype._toBer = function(ber) { +CompareRequest.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.entry.toString()); @@ -70,7 +70,7 @@ CompareRequest.prototype._toBer = function(ber) { }; -CompareRequest.prototype._json = function(j) { +CompareRequest.prototype._json = function (j) { assert.ok(j); j.entry = this.entry.toString(); diff --git a/lib/messages/compare_response.js b/lib/messages/compare_response.js index de7a7b7..33289d0 100644 --- a/lib/messages/compare_response.js +++ b/lib/messages/compare_response.js @@ -11,7 +11,7 @@ var Protocol = require('../protocol'); function CompareResponse(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; @@ -24,9 +24,9 @@ util.inherits(CompareResponse, LDAPResult); module.exports = CompareResponse; -CompareResponse.prototype.end = function(matches) { +CompareResponse.prototype.end = function (matches) { var status = 0x06; - if (typeof(matches) === 'boolean') { + if (typeof (matches) === 'boolean') { if (!matches) status = 0x05; // Compare false } else { diff --git a/lib/messages/del_request.js b/lib/messages/del_request.js index bdfcf75..11cf48c 100644 --- a/lib/messages/del_request.js +++ b/lib/messages/del_request.js @@ -22,7 +22,7 @@ var Ber = asn1.Ber; function DeleteRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.entry && !(options.entry instanceof dn.DN)) throw new TypeError('options.entry must be a DN'); @@ -36,14 +36,14 @@ function DeleteRequest(options) { this.entry = options.entry || null; var self = this; - this.__defineGetter__('type', function() { return 'DeleteRequest'; }); - this.__defineGetter__('_dn', function() { return self.entry; }); + this.__defineGetter__('type', function () { return 'DeleteRequest'; }); + this.__defineGetter__('_dn', function () { return self.entry; }); } util.inherits(DeleteRequest, LDAPMessage); module.exports = DeleteRequest; -DeleteRequest.prototype._parse = function(ber, length) { +DeleteRequest.prototype._parse = function (ber, length) { assert.ok(ber); this.entry = dn.parse(ber.buffer.slice(0, length).toString('utf8')); @@ -53,7 +53,7 @@ DeleteRequest.prototype._parse = function(ber, length) { }; -DeleteRequest.prototype._toBer = function(ber) { +DeleteRequest.prototype._toBer = function (ber) { assert.ok(ber); var buf = new Buffer(this.entry.toString()); @@ -64,7 +64,7 @@ DeleteRequest.prototype._toBer = function(ber) { }; -DeleteRequest.prototype._json = function(j) { +DeleteRequest.prototype._json = function (j) { assert.ok(j); j.entry = this.entry; diff --git a/lib/messages/del_response.js b/lib/messages/del_response.js index 3da42c7..de55aa1 100644 --- a/lib/messages/del_response.js +++ b/lib/messages/del_response.js @@ -10,7 +10,7 @@ var Protocol = require('../protocol'); function DeleteResponse(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; diff --git a/lib/messages/ext_request.js b/lib/messages/ext_request.js index e7024c2..0329cdc 100644 --- a/lib/messages/ext_request.js +++ b/lib/messages/ext_request.js @@ -23,11 +23,11 @@ var Ber = asn1.Ber; function ExtendedRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); - if (options.requestName && typeof(options.requestName) !== 'string') + if (options.requestName && typeof (options.requestName) !== 'string') throw new TypeError('options.requestName must be a string'); - if (options.requestValue && typeof(options.requestValue) !== 'string') + if (options.requestValue && typeof (options.requestValue) !== 'string') throw new TypeError('options.requestValue must be a string'); } else { options = {}; @@ -39,22 +39,22 @@ function ExtendedRequest(options) { this.requestName = options.requestName || ''; this.requestValue = options.requestValue || undefined; - this.__defineGetter__('type', function() { return 'ExtendedRequest'; }); - this.__defineGetter__('_dn', function() { return this.requestName; }); - this.__defineGetter__('name', function() { + this.__defineGetter__('type', function () { return 'ExtendedRequest'; }); + this.__defineGetter__('_dn', function () { return this.requestName; }); + this.__defineGetter__('name', function () { return this.requestName; }); - this.__defineGetter__('value', function() { + this.__defineGetter__('value', function () { return this.requestValue; }); - this.__defineSetter__('name', function(name) { - if (typeof(name) !== 'string') + this.__defineSetter__('name', function (name) { + if (typeof (name) !== 'string') throw new TypeError('name must be a string'); this.requestName = name; }); - this.__defineSetter__('value', function(val) { - if (typeof(val) !== 'string') + this.__defineSetter__('value', function (val) { + if (typeof (val) !== 'string') throw new TypeError('value must be a string'); this.requestValue = val; @@ -64,7 +64,7 @@ util.inherits(ExtendedRequest, LDAPMessage); module.exports = ExtendedRequest; -ExtendedRequest.prototype._parse = function(ber) { +ExtendedRequest.prototype._parse = function (ber) { assert.ok(ber); this.requestName = ber.readString(0x80); @@ -75,7 +75,7 @@ ExtendedRequest.prototype._parse = function(ber) { }; -ExtendedRequest.prototype._toBer = function(ber) { +ExtendedRequest.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.requestName, 0x80); @@ -86,7 +86,7 @@ ExtendedRequest.prototype._toBer = function(ber) { }; -ExtendedRequest.prototype._json = function(j) { +ExtendedRequest.prototype._json = function (j) { assert.ok(j); j.requestName = this.requestName; diff --git a/lib/messages/ext_response.js b/lib/messages/ext_response.js index d325f5e..91360c7 100644 --- a/lib/messages/ext_response.js +++ b/lib/messages/ext_response.js @@ -11,11 +11,11 @@ var Protocol = require('../protocol'); function ExtendedResponse(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); - if (options.responseName && typeof(options.responseName) !== 'string') + if (options.responseName && typeof (options.responseName) !== 'string') throw new TypeError('options.responseName must be a string'); - if (options.responseValue && typeof(options.responseValue) !== 'string') + if (options.responseValue && typeof (options.responseValue) !== 'string') throw new TypeError('options.responseValue must be a string'); } else { options = {}; @@ -27,20 +27,20 @@ function ExtendedResponse(options) { options.protocolOp = Protocol.LDAP_REP_EXTENSION; LDAPResult.call(this, options); - this.__defineGetter__('name', function() { + this.__defineGetter__('name', function () { return this.responseName; }); - this.__defineGetter__('value', function() { + this.__defineGetter__('value', function () { return this.responseValue; }); - this.__defineSetter__('name', function(name) { - if (typeof(name) !== 'string') + this.__defineSetter__('name', function (name) { + if (typeof (name) !== 'string') throw new TypeError('name must be a string'); this.responseName = name; }); - this.__defineSetter__('value', function(val) { - if (typeof(val) !== 'string') + this.__defineSetter__('value', function (val) { + if (typeof (val) !== 'string') throw new TypeError('value must be a string'); this.responseValue = val; @@ -50,7 +50,7 @@ util.inherits(ExtendedResponse, LDAPResult); module.exports = ExtendedResponse; -ExtendedResponse.prototype._parse = function(ber) { +ExtendedResponse.prototype._parse = function (ber) { assert.ok(ber); if (!LDAPResult.prototype._parse.call(this, ber)) @@ -65,7 +65,7 @@ ExtendedResponse.prototype._parse = function(ber) { }; -ExtendedResponse.prototype._toBer = function(ber) { +ExtendedResponse.prototype._toBer = function (ber) { assert.ok(ber); if (!LDAPResult.prototype._toBer.call(this, ber)) @@ -80,7 +80,7 @@ ExtendedResponse.prototype._toBer = function(ber) { }; -ExtendedResponse.prototype._json = function(j) { +ExtendedResponse.prototype._json = function (j) { assert.ok(j); j = LDAPResult.prototype._json.call(this, j); diff --git a/lib/messages/message.js b/lib/messages/message.js index 5ddaab7..2f2dda4 100644 --- a/lib/messages/message.js +++ b/lib/messages/message.js @@ -30,7 +30,7 @@ var getControl = require('../controls').getControl; * @param {Object} options stuff. */ function LDAPMessage(options) { - if (!options || typeof(options) !== 'object') + if (!options || typeof (options) !== 'object') throw new TypeError('options (object) required'); this.messageID = options.messageID || 0; @@ -40,10 +40,10 @@ function LDAPMessage(options) { this.log4js = options.log4js || logStub; var self = this; - this.__defineGetter__('id', function() { return self.messageID; }); - this.__defineGetter__('dn', function() { return self._dn || ''; }); - this.__defineGetter__('type', function() { return 'LDAPMessage'; }); - this.__defineGetter__('json', function() { + this.__defineGetter__('id', function () { return self.messageID; }); + this.__defineGetter__('dn', function () { return self._dn || ''; }); + this.__defineGetter__('type', function () { return 'LDAPMessage'; }); + this.__defineGetter__('json', function () { var j = { messageID: self.messageID, protocolOp: self.type @@ -52,7 +52,7 @@ function LDAPMessage(options) { j.controls = self.controls; return j; }); - this.__defineGetter__('log', function() { + this.__defineGetter__('log', function () { if (!self._log) self._log = self.log4js.getLogger(self.type); return self._log; @@ -61,12 +61,12 @@ function LDAPMessage(options) { module.exports = LDAPMessage; -LDAPMessage.prototype.toString = function() { +LDAPMessage.prototype.toString = function () { return JSON.stringify(this.json); }; -LDAPMessage.prototype.parse = function(ber) { +LDAPMessage.prototype.parse = function (ber) { assert.ok(ber); if (this.log.isTraceEnabled()) @@ -92,7 +92,7 @@ LDAPMessage.prototype.parse = function(ber) { }; -LDAPMessage.prototype.toBer = function() { +LDAPMessage.prototype.toBer = function () { var writer = new BerWriter(); writer.startSequence(); writer.writeInt(this.messageID); @@ -104,7 +104,7 @@ LDAPMessage.prototype.toBer = function() { if (this.controls && this.controls.length) { writer.startSequence(0xa0); - this.controls.forEach(function(c) { + this.controls.forEach(function (c) { c.toBer(writer); }); writer.endSequence(); diff --git a/lib/messages/moddn_request.js b/lib/messages/moddn_request.js index cdeab0f..76052b5 100644 --- a/lib/messages/moddn_request.js +++ b/lib/messages/moddn_request.js @@ -22,14 +22,14 @@ var Ber = asn1.Ber; function ModifyDNRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.entry && !(options.entry instanceof dn.DN)) throw new TypeError('options.entry must be a DN'); if (options.newRdn && !(options.newRdn instanceof dn.DN)) throw new TypeError('options.newRdn must be a DN'); if (options.deleteOldRdn !== undefined && - typeof(options.deleteOldRdn) !== 'boolean') + typeof (options.deleteOldRdn) !== 'boolean') throw new TypeError('options.deleteOldRdn must be a boolean'); if (options.newSuperior && !(options.newSuperior instanceof dn.DN)) throw new TypeError('options.newSuperior must be a DN'); @@ -47,14 +47,14 @@ function ModifyDNRequest(options) { this.newSuperior = options.newSuperior || null; var self = this; - this.__defineGetter__('type', function() { return 'ModifyDNRequest'; }); - this.__defineGetter__('_dn', function() { return self.entry; }); + this.__defineGetter__('type', function () { return 'ModifyDNRequest'; }); + this.__defineGetter__('_dn', function () { return self.entry; }); } util.inherits(ModifyDNRequest, LDAPMessage); module.exports = ModifyDNRequest; -ModifyDNRequest.prototype._parse = function(ber) { +ModifyDNRequest.prototype._parse = function (ber) { assert.ok(ber); this.entry = dn.parse(ber.readString()); @@ -67,7 +67,7 @@ ModifyDNRequest.prototype._parse = function(ber) { }; -ModifyDNRequest.prototype._toBer = function(ber) { +ModifyDNRequest.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.entry.toString()); @@ -80,7 +80,7 @@ ModifyDNRequest.prototype._toBer = function(ber) { }; -ModifyDNRequest.prototype._json = function(j) { +ModifyDNRequest.prototype._json = function (j) { assert.ok(j); j.entry = this.entry.toString(); diff --git a/lib/messages/moddn_response.js b/lib/messages/moddn_response.js index a24a012..288cfe8 100644 --- a/lib/messages/moddn_response.js +++ b/lib/messages/moddn_response.js @@ -10,7 +10,7 @@ var Protocol = require('../protocol'); function ModifyDNResponse(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; diff --git a/lib/messages/modify_request.js b/lib/messages/modify_request.js index 8ce17af..bdd0043 100644 --- a/lib/messages/modify_request.js +++ b/lib/messages/modify_request.js @@ -7,6 +7,7 @@ var LDAPMessage = require('./message'); var LDAPResult = require('./result'); var dn = require('../dn'); +var Attribute = require('../attribute'); var Change = require('../change'); var Protocol = require('../protocol'); @@ -16,14 +17,14 @@ var Protocol = require('../protocol'); function ModifyRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.object && !(options.object instanceof dn.DN)) throw new TypeError('options.object must be a DN'); if (options.attributes) { if (!Array.isArray(options.attributes)) throw new TypeError('options.attributes must be [Attribute]'); - options.attributes.forEach(function(a) { + options.attributes.forEach(function (a) { if (!(a instanceof Attribute)) throw new TypeError('options.attributes must be [Attribute]'); }); @@ -39,14 +40,14 @@ function ModifyRequest(options) { this.changes = options.changes ? options.changes.slice(0) : []; var self = this; - this.__defineGetter__('type', function() { return 'ModifyRequest'; }); - this.__defineGetter__('_dn', function() { return self.object; }); + this.__defineGetter__('type', function () { return 'ModifyRequest'; }); + this.__defineGetter__('_dn', function () { return self.object; }); } util.inherits(ModifyRequest, LDAPMessage); module.exports = ModifyRequest; -ModifyRequest.prototype._parse = function(ber) { +ModifyRequest.prototype._parse = function (ber) { assert.ok(ber); this.object = dn.parse(ber.readString()); @@ -65,12 +66,12 @@ ModifyRequest.prototype._parse = function(ber) { }; -ModifyRequest.prototype._toBer = function(ber) { +ModifyRequest.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.object.toString()); ber.startSequence(); - this.changes.forEach(function(c) { + this.changes.forEach(function (c) { c.toBer(ber); }); ber.endSequence(); @@ -79,13 +80,13 @@ ModifyRequest.prototype._toBer = function(ber) { }; -ModifyRequest.prototype._json = function(j) { +ModifyRequest.prototype._json = function (j) { assert.ok(j); j.object = this.object; j.changes = []; - this.changes.forEach(function(c) { + this.changes.forEach(function (c) { j.changes.push(c.json); }); diff --git a/lib/messages/modify_response.js b/lib/messages/modify_response.js index c53502f..deecd4c 100644 --- a/lib/messages/modify_response.js +++ b/lib/messages/modify_response.js @@ -10,7 +10,7 @@ var Protocol = require('../protocol'); function ModifyResponse(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; diff --git a/lib/messages/parser.js b/lib/messages/parser.js index 92fa003..b2e5f7a 100644 --- a/lib/messages/parser.js +++ b/lib/messages/parser.js @@ -48,9 +48,9 @@ var BerReader = asn1.BerReader; ///--- API function Parser(options) { - if (!options || typeof(options) !== 'object') + if (!options || typeof (options) !== 'object') throw new TypeError('options (object) required'); - if (!options.log4js || typeof(options.log4js) !== 'object') + if (!options.log4js || typeof (options.log4js) !== 'object') throw new TypeError('options.log4js (object) required'); EventEmitter.call(this); @@ -63,11 +63,10 @@ util.inherits(Parser, EventEmitter); module.exports = Parser; -Parser.prototype.write = function(data) { +Parser.prototype.write = function (data) { if (!data || !Buffer.isBuffer(data)) throw new TypeError('data (buffer) required'); - var log = this.log; var nextMessage = null; var self = this; @@ -113,10 +112,9 @@ Parser.prototype.write = function(data) { }; -Parser.prototype.getMessage = function(ber) { +Parser.prototype.getMessage = function (ber) { assert.ok(ber); - var log = this.log; var self = this; var messageID = ber.readInt(); @@ -209,8 +207,7 @@ Parser.prototype.getMessage = function(ber) { this.emit('error', new Error('protocolOp 0x' + (type ? type.toString(16) : '??') + - ' not supported' - ), + ' not supported'), new LDAPResult({ messageID: messageID, protocolOp: type || Protocol.LDAP_REP_EXTENSION @@ -225,4 +222,3 @@ Parser.prototype.getMessage = function(ber) { log4js: self.log4js }); }; - diff --git a/lib/messages/result.js b/lib/messages/result.js index 36b9632..3c437bf 100644 --- a/lib/messages/result.js +++ b/lib/messages/result.js @@ -22,20 +22,20 @@ var BerWriter = asn1.BerWriter; function LDAPResult(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options (object) required'); - if (options.status && typeof(options.status) !== 'number') + if (options.status && typeof (options.status) !== 'number') throw new TypeError('options.status must be a number'); - if (options.matchedDN && typeof(options.matchedDN) !== 'string') + if (options.matchedDN && typeof (options.matchedDN) !== 'string') throw new TypeError('options.matchedDN must be a string'); - if (options.errorMessage && typeof(options.errorMessage) !== 'string') + if (options.errorMessage && typeof (options.errorMessage) !== 'string') throw new TypeError('options.errorMessage must be a string'); if (options.referrals) { if (!(options.referrals instanceof Array)) throw new TypeError('options.referrrals must be an array[string]'); - options.referrals.forEach(function(r) { - if (typeof(r) !== 'string') + options.referrals.forEach(function (r) { + if (typeof (r) !== 'string') throw new TypeError('options.referrals must be an array[string]'); }); } @@ -52,16 +52,16 @@ function LDAPResult(options) { this.connection = options.connection || null; - this.__defineGetter__('type', function() { return 'LDAPResult'; }); + this.__defineGetter__('type', function () { return 'LDAPResult'; }); } util.inherits(LDAPResult, LDAPMessage); module.exports = LDAPResult; -LDAPResult.prototype.end = function(status) { +LDAPResult.prototype.end = function (status) { assert.ok(this.connection); - if (typeof(status) === 'number') + if (typeof (status) === 'number') this.status = status; var ber = this.toBer(); @@ -73,7 +73,7 @@ LDAPResult.prototype.end = function(status) { this.connection.write(ber); if (self._dtraceOp && self._dtraceId) { - dtrace.fire('server-' + self._dtraceOp + '-done', function() { + dtrace.fire('server-' + self._dtraceOp + '-done', function () { var c = self.connection || {ldap: {}}; return [ self._dtraceId || 0, @@ -94,7 +94,7 @@ LDAPResult.prototype.end = function(status) { }; -LDAPResult.prototype._parse = function(ber) { +LDAPResult.prototype._parse = function (ber) { assert.ok(ber); this.status = ber.readEnumeration(); @@ -113,7 +113,7 @@ LDAPResult.prototype._parse = function(ber) { }; -LDAPResult.prototype._toBer = function(ber) { +LDAPResult.prototype._toBer = function (ber) { assert.ok(ber); ber.writeEnumeration(this.status); @@ -130,7 +130,7 @@ LDAPResult.prototype._toBer = function(ber) { }; -LDAPResult.prototype._json = function(j) { +LDAPResult.prototype._json = function (j) { assert.ok(j); j.status = this.status; diff --git a/lib/messages/search_entry.js b/lib/messages/search_entry.js index f326be2..3daa52c 100644 --- a/lib/messages/search_entry.js +++ b/lib/messages/search_entry.js @@ -22,7 +22,7 @@ var BerWriter = asn1.BerWriter; function SearchEntry(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.objectName && !(options.objectName instanceof dn.DN)) throw new TypeError('options.objectName must be a DN'); @@ -37,13 +37,13 @@ function SearchEntry(options) { this.setAttributes(options.attributes || []); var self = this; - this.__defineGetter__('type', function() { return 'SearchEntry'; }); - this.__defineGetter__('object', function() { + this.__defineGetter__('type', function () { return 'SearchEntry'; }); + this.__defineGetter__('object', function () { var obj = { dn: self.dn.toString(), controls: [] }; - self.attributes.forEach(function(a) { + self.attributes.forEach(function (a) { if (a.vals && a.vals.length) { if (a.vals.length > 1) { obj[a.type] = a.vals.slice(); @@ -54,12 +54,12 @@ function SearchEntry(options) { obj[a.type] = []; } }); - self.controls.forEach(function(element, index, array) { + self.controls.forEach(function (element, index, array) { obj.controls.push(element.json); }); return obj; }); - this.__defineGetter__('_dn', function() { + this.__defineGetter__('_dn', function () { return self.objectName; }); } @@ -67,21 +67,21 @@ util.inherits(SearchEntry, LDAPMessage); module.exports = SearchEntry; -SearchEntry.prototype.addAttribute = function(attr) { - if (!attr || typeof(attr) !== 'object') +SearchEntry.prototype.addAttribute = function (attr) { + if (!attr || typeof (attr) !== 'object') throw new TypeError('attr (attribute) required'); this.attributes.push(attr); }; -SearchEntry.prototype.toObject = function() { +SearchEntry.prototype.toObject = function () { return this.object; }; -SearchEntry.prototype.fromObject = function(obj) { - if (typeof(obj) !== 'object') +SearchEntry.prototype.fromObject = function (obj) { + if (typeof (obj) !== 'object') throw new TypeError('object required'); var self = this; @@ -92,19 +92,19 @@ SearchEntry.prototype.fromObject = function(obj) { obj = obj.attributes; this.attributes = []; - Object.keys(obj).forEach(function(k) { + Object.keys(obj).forEach(function (k) { self.attributes.push(new Attribute({type: k, vals: obj[k]})); }); return true; }; -SearchEntry.prototype.setAttributes = function(obj) { - if (typeof(obj) !== 'object') +SearchEntry.prototype.setAttributes = function (obj) { + if (typeof (obj) !== 'object') throw new TypeError('object required'); if (Array.isArray(obj)) { - obj.forEach(function(a) { + obj.forEach(function (a) { if (!Attribute.isAttribute(a)) throw new TypeError('entry must be an Array of Attributes'); }); @@ -113,10 +113,10 @@ SearchEntry.prototype.setAttributes = function(obj) { var self = this; self.attributes = []; - Object.keys(obj).forEach(function(k) { + Object.keys(obj).forEach(function (k) { var attr = new Attribute({type: k}); if (Array.isArray(obj[k])) { - obj[k].forEach(function(v) { + obj[k].forEach(function (v) { attr.addValue(v.toString()); }); } else { @@ -128,12 +128,12 @@ SearchEntry.prototype.setAttributes = function(obj) { }; -SearchEntry.prototype._json = function(j) { +SearchEntry.prototype._json = function (j) { assert.ok(j); j.objectName = this.objectName.toString(); j.attributes = []; - this.attributes.forEach(function(a) { + this.attributes.forEach(function (a) { j.attributes.push(a.json || a); }); @@ -141,7 +141,7 @@ SearchEntry.prototype._json = function(j) { }; -SearchEntry.prototype._parse = function(ber) { +SearchEntry.prototype._parse = function (ber) { assert.ok(ber); this.objectName = ber.readString(); @@ -158,12 +158,12 @@ SearchEntry.prototype._parse = function(ber) { }; -SearchEntry.prototype._toBer = function(ber) { +SearchEntry.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.objectName.toString()); ber.startSequence(); - this.attributes.forEach(function(a) { + this.attributes.forEach(function (a) { // This may or may not be an attribute ber = Attribute.toBer(a, ber); }); @@ -171,6 +171,3 @@ SearchEntry.prototype._toBer = function(ber) { return ber; }; - - - diff --git a/lib/messages/search_reference.js b/lib/messages/search_reference.js index cfa8908..2b1ee9e 100644 --- a/lib/messages/search_reference.js +++ b/lib/messages/search_reference.js @@ -23,7 +23,7 @@ var parseURL = url.parse; function SearchReference(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.objectName && !(options.objectName instanceof dn.DN)) throw new TypeError('options.objectName must be a DN'); @@ -37,20 +37,20 @@ function SearchReference(options) { this.uris = options.uris || []; var self = this; - this.__defineGetter__('type', function() { return 'SearchReference'; }); - this.__defineGetter__('object', function() { + this.__defineGetter__('type', function () { return 'SearchReference'; }); + this.__defineGetter__('object', function () { return { dn: self.dn.toString(), uris: self.uris.slice() }; }); - this.__defineGetter__('_dn', function() { + this.__defineGetter__('_dn', function () { return new dn.DN(''); }); - this.__defineGetter__('urls', function() { + this.__defineGetter__('urls', function () { return self.uris; }); - this.__defineSetter__('urls', function(u) { + this.__defineSetter__('urls', function (u) { self.uris = u.slice(); }); } @@ -58,13 +58,13 @@ util.inherits(SearchReference, LDAPMessage); module.exports = SearchReference; -SearchReference.prototype.toObject = function() { +SearchReference.prototype.toObject = function () { return this.object; }; -SearchReference.prototype.fromObject = function(obj) { - if (typeof(obj) !== 'object') +SearchReference.prototype.fromObject = function (obj) { + if (typeof (obj) !== 'object') throw new TypeError('object required'); this.uris = obj.uris ? obj.uris.slice() : []; @@ -72,14 +72,14 @@ SearchReference.prototype.fromObject = function(obj) { return true; }; -SearchReference.prototype._json = function(j) { +SearchReference.prototype._json = function (j) { assert.ok(j); j.uris = this.uris.slice(); return j; }; -SearchReference.prototype._parse = function(ber, length) { +SearchReference.prototype._parse = function (ber, length) { assert.ok(ber); while (ber.offset < length) { @@ -92,15 +92,12 @@ SearchReference.prototype._parse = function(ber, length) { }; -SearchReference.prototype._toBer = function(ber) { +SearchReference.prototype._toBer = function (ber) { assert.ok(ber); - this.uris.forEach(function(u) { + this.uris.forEach(function (u) { ber.writeString(u.href || u); }); return ber; }; - - - diff --git a/lib/messages/search_request.js b/lib/messages/search_request.js index bc720c0..a31e49a 100644 --- a/lib/messages/search_request.js +++ b/lib/messages/search_request.js @@ -24,7 +24,7 @@ var Ber = asn1.Ber; function SearchRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; @@ -34,11 +34,11 @@ function SearchRequest(options) { LDAPMessage.call(this, options); var self = this; - this.__defineGetter__('type', function() { return 'SearchRequest'; }); - this.__defineGetter__('_dn', function() { + this.__defineGetter__('type', function () { return 'SearchRequest'; }); + this.__defineGetter__('_dn', function () { return self.baseObject; }); - this.__defineGetter__('scope', function() { + this.__defineGetter__('scope', function () { switch (self._scope) { case Protocol.SCOPE_BASE_OBJECT: return 'base'; case Protocol.SCOPE_ONE_LEVEL: return 'one'; @@ -47,8 +47,8 @@ function SearchRequest(options) { throw new Error(self._scope + ' is an invalid search scope'); } }); - this.__defineSetter__('scope', function(s) { - if (typeof(s) === 'string') { + this.__defineSetter__('scope', function (s) { + if (typeof (s) === 'string') { switch (s) { case 'base': self._scope = Protocol.SCOPE_BASE_OBJECT; @@ -67,7 +67,7 @@ function SearchRequest(options) { } }); - this.baseObject = options.baseObject || new dn.DN([{}]); + this.baseObject = options.baseObject || new dn.DN([ {} ]); this.scope = options.scope || 'base'; this.derefAliases = options.derefAliases || Protocol.NEVER_DEREF_ALIASES; this.sizeLimit = options.sizeLimit || 0; @@ -80,7 +80,7 @@ util.inherits(SearchRequest, LDAPMessage); module.exports = SearchRequest; -SearchRequest.prototype.newResult = function() { +SearchRequest.prototype.newResult = function () { var self = this; return new LDAPResult({ @@ -90,7 +90,7 @@ SearchRequest.prototype.newResult = function() { }; -SearchRequest.prototype._parse = function(ber) { +SearchRequest.prototype._parse = function (ber) { assert.ok(ber); this.baseObject = dn.parse(ber.readString()); @@ -114,7 +114,7 @@ SearchRequest.prototype._parse = function(ber) { }; -SearchRequest.prototype._toBer = function(ber) { +SearchRequest.prototype._toBer = function (ber) { assert.ok(ber); ber.writeString(this.baseObject.toString()); @@ -129,7 +129,7 @@ SearchRequest.prototype._toBer = function(ber) { ber.startSequence(Ber.Sequence | Ber.Constructor); if (this.attributes && this.attributes.length) { - this.attributes.forEach(function(a) { + this.attributes.forEach(function (a) { ber.writeString(a); }); } @@ -139,7 +139,7 @@ SearchRequest.prototype._toBer = function(ber) { }; -SearchRequest.prototype._json = function(j) { +SearchRequest.prototype._json = function (j) { assert.ok(j); j.baseObject = this.baseObject; diff --git a/lib/messages/search_response.js b/lib/messages/search_response.js index 0fa4ce8..e0f3c00 100644 --- a/lib/messages/search_response.js +++ b/lib/messages/search_response.js @@ -19,7 +19,7 @@ var Protocol = require('../protocol'); function SearchResponse(options) { if (!options) options = {}; - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); options.protocolOp = Protocol.LDAP_REP_SEARCH; @@ -40,12 +40,12 @@ module.exports = SearchResponse; * @param {Boolean} nofiltering skip filtering notAttributes and '_' attributes. * Defaults to 'false'. */ -SearchResponse.prototype.send = function(entry, nofiltering) { - if (!entry || typeof(entry) !== 'object') +SearchResponse.prototype.send = function (entry, nofiltering) { + if (!entry || typeof (entry) !== 'object') throw new TypeError('entry (SearchEntry) required'); if (nofiltering === undefined) nofiltering = false; - if (typeof(nofiltering) !== 'boolean') + if (typeof (nofiltering) !== 'boolean') throw new TypeError('noFiltering must be a boolean'); var self = this; @@ -61,7 +61,7 @@ SearchResponse.prototype.send = function(entry, nofiltering) { var savedAttrs = {}; var all = (self.attributes.indexOf('*') !== -1); - Object.keys(entry.attributes).forEach(function(a) { + Object.keys(entry.attributes).forEach(function (a) { var _a = a.toLowerCase(); if (!nofiltering && _a.length && _a[0] === '_') { savedAttrs[a] = entry.attributes[a]; @@ -70,7 +70,7 @@ SearchResponse.prototype.send = function(entry, nofiltering) { savedAttrs[a] = entry.attributes[a]; delete entry.attributes[a]; } else if (all) { - // noop + return; } else if (self.attributes.length && self.attributes.indexOf(_a) === -1) { savedAttrs[a] = entry.attributes[a]; delete entry.attributes[a]; @@ -79,7 +79,7 @@ SearchResponse.prototype.send = function(entry, nofiltering) { var save = entry; entry = new SearchEntry({ - objectName: typeof(save.dn) === 'string' ? parseDN(save.dn) : save.dn, + objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn, messageID: self.messageID, log4js: self.log4js }); @@ -94,7 +94,7 @@ SearchResponse.prototype.send = function(entry, nofiltering) { this.sentEntries++; if (self._dtraceOp && self._dtraceId) { - dtrace.fire('server-search-entry', function() { + dtrace.fire('server-search-entry', function () { var c = self.connection || {ldap: {}}; return [ self._dtraceId || 0, @@ -108,7 +108,7 @@ SearchResponse.prototype.send = function(entry, nofiltering) { } // Restore attributes - Object.keys(savedAttrs).forEach(function(k) { + Object.keys(savedAttrs).forEach(function (k) { save.attributes[k] = savedAttrs[k]; }); @@ -120,8 +120,8 @@ SearchResponse.prototype.send = function(entry, nofiltering) { -SearchResponse.prototype.createSearchEntry = function(object) { - if (!object || typeof(object) !== 'object') +SearchResponse.prototype.createSearchEntry = function (object) { + if (!object || typeof (object) !== 'object') throw new TypeError('object required'); var self = this; @@ -137,7 +137,7 @@ SearchResponse.prototype.createSearchEntry = function(object) { }; -SearchResponse.prototype.createSearchReference = function(uris) { +SearchResponse.prototype.createSearchReference = function (uris) { if (!uris) throw new TypeError('uris ([string]) required'); @@ -145,7 +145,7 @@ SearchResponse.prototype.createSearchReference = function(uris) { uris = [uris]; for (var i = 0; i < uris.length; i++) { - if (typeof(uris[i]) == 'string') + if (typeof (uris[i]) == 'string') uris[i] = parseURL(uris[i]); } diff --git a/lib/messages/unbind_request.js b/lib/messages/unbind_request.js index 79f4a1f..224fad1 100644 --- a/lib/messages/unbind_request.js +++ b/lib/messages/unbind_request.js @@ -25,7 +25,7 @@ var RDN = dn.RDN; function UnbindRequest(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); } else { options = {}; @@ -35,8 +35,8 @@ function UnbindRequest(options) { LDAPMessage.call(this, options); var self = this; - this.__defineGetter__('type', function() { return 'UnbindRequest'; }); - this.__defineGetter__('_dn', function() { + this.__defineGetter__('type', function () { return 'UnbindRequest'; }); + this.__defineGetter__('_dn', function () { if (self.connection) return self.connection.ldap.bindDN; @@ -47,21 +47,19 @@ util.inherits(UnbindRequest, LDAPMessage); module.exports = UnbindRequest; -UnbindRequest.prototype.newResult = function() { - var self = this; - +UnbindRequest.prototype.newResult = function () { // This one is special, so just hack up the result object function UnbindResponse(options) { LDAPMessage.call(this, options); - this.__defineGetter__('type', function() { return 'UnbindResponse'; }); + this.__defineGetter__('type', function () { return 'UnbindResponse'; }); } util.inherits(UnbindResponse, LDAPMessage); - UnbindResponse.prototype.end = function(status) { + UnbindResponse.prototype.end = function (status) { if (this.log.isTraceEnabled()) - log.trace('%s: unbinding!', this.connection.ldap.id); + this.log.trace('%s: unbinding!', this.connection.ldap.id); this.connection.end(); }; - UnbindResponse.prototype._json = function(j) { return j; }; + UnbindResponse.prototype._json = function (j) { return j; }; return new UnbindResponse({ messageID: 0, @@ -71,21 +69,21 @@ UnbindRequest.prototype.newResult = function() { }; -UnbindRequest.prototype._parse = function(ber) { +UnbindRequest.prototype._parse = function (ber) { assert.ok(ber); return true; }; -UnbindRequest.prototype._toBer = function(ber) { +UnbindRequest.prototype._toBer = function (ber) { assert.ok(ber); return ber; }; -UnbindRequest.prototype._json = function(j) { +UnbindRequest.prototype._json = function (j) { assert.ok(j); return j; diff --git a/lib/messages/unbind_response.js b/lib/messages/unbind_response.js index 21ff8ce..1fb209e 100644 --- a/lib/messages/unbind_response.js +++ b/lib/messages/unbind_response.js @@ -17,12 +17,12 @@ var Protocol = require('../protocol'); function UnbindResponse(options) { if (!options) options = {}; - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options must be an object'); options.protocolOp = 0; LDAPMessage.call(this, options); - this.__defineGetter__('type', function() { return 'UnbindResponse'; }); + this.__defineGetter__('type', function () { return 'UnbindResponse'; }); } util.inherits(UnbindResponse, LDAPMessage); module.exports = UnbindResponse; @@ -33,7 +33,7 @@ module.exports = UnbindResponse; * * @param {Number} status completely ignored. */ -UnbindResponse.prototype.end = function(status) { +UnbindResponse.prototype.end = function (status) { assert.ok(this.connection); if (this.log.isTraceEnabled()) @@ -43,7 +43,7 @@ UnbindResponse.prototype.end = function(status) { var self = this; if (self._dtraceOp && self._dtraceId) { - dtrace.fire('server-' + self._dtraceOp + '-done', function() { + dtrace.fire('server-' + self._dtraceOp + '-done', function () { var c = self.connection || {ldap: {}}; return [ self._dtraceId || 0, @@ -58,6 +58,6 @@ UnbindResponse.prototype.end = function(status) { }; -UnbindResponse.prototype._json = function(j) { +UnbindResponse.prototype._json = function (j) { return j; }; diff --git a/lib/schema/add_handler.js b/lib/schema/add_handler.js deleted file mode 100644 index 4ef16a8..0000000 --- a/lib/schema/add_handler.js +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2011 Mark Cavage, Inc. All rights reserved. - -var assert = require('assert'); - -var dn = require('../dn'); -var errors = require('../errors'); -var logStub = require('../log_stub'); - -var getTransformer = require('./transform').getTransformer; - - - -function createAddHandler(options) { - if (!options || typeof(options) !== 'object') - throw new TypeError('options (object) required'); - if (!options.schema || typeof(options.schema) !== 'object') - throw new TypeError('options.schema (object) required'); - - var log4js = options.log4js || logStub; - var log = log4js.getLogger('SchemaAddHandler'); - var schema = options.schema; - - if (log.isDebugEnabled()) - log.debug('Creating add schema handler with: %s', - JSON.stringify(options.schema, null, 2)); - - var CVErr = errors.ConstraintViolationError; - var NSAErr = errors.NoSuchAttributeError; - var OCVErr = errors.ObjectclassViolationError; - - return function schemaAddHandler(req, res, next) { - var allowed = []; - var attributes = req.toObject().attributes; - var attrNames = Object.keys(attributes); - var i; - var j; - var k; - var key; - - if (log.isDebugEnabled()) - log.debug('%s running %j against schema', req.logId, attributes); - - if (!attributes.objectclass) - return next(new OCVErr('no objectclass')); - - for (i = 0; i < attributes.objectclass.length; i++) { - var oc = attributes.objectclass[i].toLowerCase(); - if (!schema.objectclasses[oc]) - return next(new NSAErr(oc + ' is not a known objectClass')); - - // We can check required attributes right here in line. Mays we have to - // get the complete set of though. Also, to make checking much simpler, - // we just push the musts into the may list. - var must = schema.objectclasses[oc].must; - for (j = 0; j < must.length; j++) { - if (attrNames.indexOf(must[j]) === -1) - return next(new OCVErr(must[j] + ' is a required attribute')); - if (allowed.indexOf(must[j]) === -1) - allowed.push(must[j]); - } - - schema.objectclasses[oc].may.forEach(function(attr) { - if (allowed.indexOf(attr) === -1) - allowed.push(attr); - }); - } - - // Now check that the entry's attributes are in the allowed list, and go - // ahead and transform the values as appropriate - for (i = 0; i < attrNames.length; i++) { - key = attrNames[i]; - if (allowed.indexOf(key) === -1) - return next(new OCVErr(key + ' is not valid for the objectClasses ' + - attributes.objectclass.join())); - - var transform = getTransformer(schema, key); - if (transform) { - for (j = 0; j < attributes[key].length; j++) { - try { - attributes[key][j] = transform(attributes[key][j]); - } catch (e) { - log.debug('%s Error parsing %s: %s', req.logId, k, - attributes[key][j], - e.stack); - return next(new CVErr(attrNames[i])); - } - } - for (j = 0; j < req.attributes.length; j++) { - if (req.attributes[j].type === key) { - req.attributes[j].vals = attributes[key]; - break; - } - } - } - } - - return next(); - }; -} - -module.exports = createAddHandler; - - // Now we have a modified attributes object we want to update - // "transparently" in the request. - // if (xformedValues) { - // attrNames.forEach(function(k) { - // for (var i = 0; i < req.attributes.length; i++) { - // if (req.attributes[i].type === k) { - // req.attributes[i].vals = attributes[k]; - // return; - // } - // } - // }); - // } - diff --git a/lib/schema/index.js b/lib/schema/index.js deleted file mode 100644 index 9e28b20..0000000 --- a/lib/schema/index.js +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2011 Mark Cavage, Inc. All rights reserved. - -var createAddHandler = require('./add_handler'); -var createModifyHandler = require('./mod_handler'); -var createSearchHandler = require('./search_handler'); -var parser = require('./parser'); - - - -///--- API - -module.exports = { - - createAddHandler: createAddHandler, - - createModifyHandler: createModifyHandler, - - createSearchHandler: createSearchHandler, - - load: parser.load - -}; diff --git a/lib/schema/mod_handler.js b/lib/schema/mod_handler.js deleted file mode 100644 index 8e206a4..0000000 --- a/lib/schema/mod_handler.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2011 Mark Cavage, Inc. All rights reserved. - -var assert = require('assert'); - -var dn = require('../dn'); -var errors = require('../errors'); -var logStub = require('../log_stub'); - -var getTransformer = require('./transform').getTransformer; - - - -function createModifyHandler(options) { - if (!options || typeof(options) !== 'object') - throw new TypeError('options (object) required'); - if (!options.schema || typeof(options.schema) !== 'object') - throw new TypeError('options.schema (object) required'); - // TODO add a callback mechanism here so objectclass constraints can be - // enforced - - var log4js = options.log4js || logStub; - var log = log4js.getLogger('SchemaModifyHandler'); - var schema = options.schema; - - var CVErr = errors.ConstraintViolationError; - var NSAErr = errors.NoSuchAttributeError; - var OCVErr = errors.ObjectclassViolationError; - - return function schemaModifyHandler(req, res, next) { - if (log.isDebugEnabled()) - log.debug('%s running %j against schema', req.logId, req.changes); - - for (var i = 0; i < req.changes.length; i++) { - var mod = req.changes[i].modification; - var attribute = schema.attributes[mod.type]; - if (!attribute) - return next(new NSAErr(mod.type)); - - if (!mod.vals || !mod.vals.length) - continue; - - var transform = getTransformer(schema, mod.type); - if (transform) { - for (var j = 0; j < mod.vals.length; j++) { - try { - mod.vals[j] = transform(mod.vals[j]); - } catch (e) { - log.debug('%s Error parsing %s: %s', req.logId, mod.vals[j], - e.stack); - return next(new CVErr(mod.type + ': ' + mod.vals[j])); - } - } - } - } - return next(); - } -} - -module.exports = createModifyHandler; diff --git a/lib/schema/parser.js b/lib/schema/parser.js deleted file mode 100644 index aa85b20..0000000 --- a/lib/schema/parser.js +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright 2011 Mark Cavage, Inc. All rights reserved. - -var assert = require('assert'); -var fs = require('fs'); - -var dn = require('../dn'); -var errors = require('../errors'); -var logStub = require('../log_stub'); - - - -//// Attribute BNF -// -// AttributeTypeDescription = "(" whsp -// numericoid whsp ; AttributeType identifier -// [ "NAME" qdescrs ] ; name used in AttributeType -// [ "DESC" qdstring ] ; description -// [ "OBSOLETE" whsp ] -// [ "SUP" woid ] ; derived from this other -// ; AttributeType -// [ "EQUALITY" woid ; Matching Rule name -// [ "ORDERING" woid ; Matching Rule name -// [ "SUBSTR" woid ] ; Matching Rule name -// [ "SYNTAX" whsp noidlen whsp ] ; Syntax OID -// [ "SINGLE-VALUE" whsp ] ; default multi-valued -// [ "COLLECTIVE" whsp ] ; default not collective -// [ "NO-USER-MODIFICATION" whsp ]; default user modifiable -// [ "USAGE" whsp AttributeUsage ]; default userApplications -// whsp ")" -// -// AttributeUsage = -// "userApplications" / -// "directoryOperation" / -// "distributedOperation" / ; DSA-shared -// "dSAOperation" ; DSA-specific, value depends on server - -/// Objectclass BNF -// -// ObjectClassDescription = "(" whsp -// numericoid whsp ; ObjectClass identifier -// [ "NAME" qdescrs ] -// [ "DESC" qdstring ] -// [ "OBSOLETE" whsp ] -// [ "SUP" oids ] ; Superior ObjectClasses -// [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ] -// ; default structural -// [ "MUST" oids ] ; AttributeTypes -// [ "MAY" oids ] ; AttributeTypes -// whsp ")" - -// This is some fugly code, and really not that robust, but LDAP schema -// is a pita with its optional ('s. So, whatever, it's good enough for our -// purposes (namely, dropping in the OpenLDAP schema). This took me a little -// over an hour to write, so there you go ;) - -function parse(data) { - if (!data || typeof(data) !== 'string') - throw new TypeError('data (string) required'); - - var lines = []; - data.split('\n').forEach(function(l) { - if (/^#/.test(l) || - /^objectidentifier/i.test(l) || - !l.length) - return; - - lines.push(l); - }); - - var attr; - var oc; - var syntax; - var attributes = []; - var objectclasses = []; - var depth = 0; - lines.join('\n').split(/\s+/).forEach(function(w) { - if (attr) { - if (w === '(') { - depth++; - } else if (w === ')') { - if (--depth === 0) { - if (attr._skip) - delete attr._skip; - - attributes.push(attr); - attr = null; - } - return; - } else if (!attr.oid) { - attr.oid = w; - } else if (w === 'NAME') { - attr._names = []; - } else if (w === 'DESC') { - attr._desc = ''; - } else if (w === 'OBSOLETE') { - attr.obsolete = true; - } else if (w === 'SUP') { - attr._sup = true; - } else if (attr._sup) { - attr.sup = w; - delete attr._sup; - } else if (w === 'EQUALITY') { - attr._equality = true; - } else if (w === 'ORDERING') { - attr._ordering = true; - } else if (w === 'SUBSTR') { - attr._substr = true; - } else if (w === 'SYNTAX') { - attr._syntax = true; - } else if (w === 'SINGLE-VALUE') { - attr.singleValue = true; - } else if (w === 'COLLECTIVE') { - attr.collective = true; - } else if (w === 'NO-USER-MODIFICATION') { - attr.noUserModification = true; - } else if (w === 'USAGE') { - attr._usage = true; - } else if (/^X-/.test(w)) { - attr._skip = true; - } else if (attr._skip) { - // noop - } else if (attr._usage) { - attr.usage = w; - delete attr._usage; - } else if (attr._syntax) { - attr.syntax = w; - delete attr._syntax; - } else if (attr._substr) { - attr.substr = w; - delete attr._substr; - } else if (attr._ordering) { - attr.ordering = w; - delete attr._ordering; - } else if (attr._equality) { - attr.equality = w; - delete attr._equality; - } else if (attr._desc !== undefined) { - attr._desc += w.replace(/\'/g, ''); - if (/\'$/.test(w)) { - attr.desc = attr._desc; - delete attr._desc; - } else { - attr._desc += ' '; - } - } else if (attr._names) { - attr._names.push(w.replace(/\'/g, '').toLowerCase()); - } - return; - } - - if (oc) { - if (w === '(') { - depth++; - } else if (w === ')') { - if (--depth === 0) { - objectclasses.push(oc); - oc = null; - } - return; - } else if (w === '$') { - return; - } else if (!oc.oid) { - oc.oid = w; - } else if (w === 'NAME') { - oc._names = []; - } else if (w === 'DESC') { - oc._desc = ''; - } else if (w === 'OBSOLETE') { - oc.obsolete = true; - } else if (w === 'SUP') { - oc._sup = []; - } else if (w === 'ABSTRACT') { - oc['abstract'] = true; - } else if (w === 'AUXILIARY') { - oc.auxiliary = true; - } else if (w === 'STRUCTURAL') { - oc.structural = true; - } else if (w === 'MUST') { - oc._must = []; - } else if (w === 'MAY') { - oc._may = []; - } else if (oc._may) { - oc._may.push(w.toLowerCase()); - } else if (oc._must) { - oc._must.push(w.toLowerCase()); - } else if (oc._sup) { - oc._sup.push(w.replace(/\'/g, '').toLowerCase()); - } else if (oc._desc !== undefined) { - oc._desc += w.replace(/\'/g, ''); - if (/\'$/.test(w)) { - oc.desc = oc._desc; - delete oc._desc; - } else { - oc._desc += ' '; - } - } else if (oc._names) { - oc._names.push(w.replace(/\'/g, '').toLowerCase()); - } - - return; - } - - // Throw this away for now. - if (syntax) { - if (w === '(') { - depth++; - } else if (w === ')') { - if (--depth === 0) { - syntax = false; - } - } - return; - } - - if (/^attributetype/i.test(w)) { - attr = {}; - } else if (/^objectclass/i.test(w)) { - oc = {}; - } else if (/^ldapsyntax/i.test(w)) { - syntax = true; - } else if (!w) { - // noop - } else { - throw new Error('Invalid token ' + w + ' in file ' + file); - } - }); - - // cleanup all the temporary arrays - var i; - for (i = 0; i < attributes.length; i++) { - if (!attributes[i]._names) - continue; - - attributes[i].names = attributes[i]._names; - delete attributes[i]._names; - } - for (i = 0; i < objectclasses.length; i++) { - oc = objectclasses[i]; - if (oc._names) { - oc.names = oc._names; - delete oc._names; - } else { - oc.names = []; - } - if (oc._sup) { - oc.sup = oc._sup; - delete oc._sup; - } else { - oc.sup = []; - } - if (oc._must) { - oc.must = oc._must; - delete oc._must; - } else { - oc.must = []; - } - if (oc._may) { - oc.may = oc._may; - delete oc._may; - } else { - oc.may = []; - } - } - - var _attributes = {}; - var _objectclasses = {}; - attributes.forEach(function(a) { - for (var i = 0; i < a.names.length; i++) { - a.names[i] = a.names[i].toLowerCase(); - _attributes[a.names[i]] = a; - } - }); - - objectclasses.forEach(function(oc) { - for (var i = 0; i < oc.names.length; i++) { - oc.names[i] = oc.names[i].toLowerCase(); - _objectclasses[oc.names[i]] = oc; - } - }); - - return { - attributes: _attributes, - objectclasses: _objectclasses - }; -} - - -function parseFile(file, callback) { - if (!file || typeof(file) !== 'string') - throw new TypeError('file (string) required'); - if (!callback || typeof(callback) !== 'function') - throw new TypeError('callback (function) required'); - - fs.readFile(file, 'utf8', function(err, data) { - if (err) - return callback(new errors.OperationsError(err.message)); - - try { - return callback(null, parse(data)); - } catch (e) { - return callback(new errors.OperationsError(e.message)); - } - }); -} - - -function _merge(child, parent) { - Object.keys(parent).forEach(function(k) { - if (Array.isArray(parent[k])) { - if (k === 'names' || k === 'sup') - return; - - if (!child[k]) - child[k] = []; - - parent[k].forEach(function(v) { - if (child[k].indexOf(v) === -1) - child[k].push(v); - }); - } else if (!child[k]) { - child[k] = parent[k]; - } - }); - - return child; -} - - -function compile(attributes, objectclasses) { - assert.ok(attributes); - assert.ok(objectclasses); - - var _attributes = {}; - var _objectclasses = {}; - - Object.keys(attributes).forEach(function(k) { - _attributes[k] = attributes[k]; - - var sup; - if (attributes[k].sup && (sup = attributes[attributes[k].sup])) - _attributes[k] = _merge(_attributes[k], sup); - - _attributes[k].names.sort(); - }); - - Object.keys(objectclasses).forEach(function(k) { - _objectclasses[k] = objectclasses[k]; - var sup; - if (objectclasses[k].sup && (sup = objectclasses[objectclasses[k].sup])) - _objectclasses[k] = _merge(_objectclasses[k], sup); - - _objectclasses[k].names.sort(); - _objectclasses[k].sup.sort(); - _objectclasses[k].must.sort(); - _objectclasses[k].may.sort(); - }); - - return { - attributes: _attributes, - objectclasses: _objectclasses - }; -} - - - -/** - * Loads all the `.schema` files in a directory, and parses them. - * - * This method returns the set of schema from all files, and the "last one" - * wins, so don't do something stupid like have the same attribute defined - * N times with varying definitions. - * - * @param {String} directory the directory of *.schema files to load. - * @param {Function} callback of the form f(err, attributes, objectclasses). - * @throws {TypeEror} on bad input. - */ -function load(directory, callback) { - if (!directory || typeof(directory) !== 'string') - throw new TypeError('directory (string) required'); - if (!callback || typeof(callback) !== 'function') - throw new TypeError('callback (function) required'); - - fs.readdir(directory, function(err, files) { - if (err) - return callback(new errors.OperationsError(err.message)); - - var finished = 0; - var attributes = {}; - var objectclasses = {}; - files.forEach(function(f) { - if (!/\.schema$/.test(f)) { - ++finished; - return; - } - - f = directory + '/' + f; - parseFile(f, function(err, schema) { - var cb = callback; - if (err) { - callback = null; - if (cb) - return cb(new errors.OperationsError(err.message)); - - return; - } - - Object.keys(schema.attributes).forEach(function(a) { - attributes[a] = schema.attributes[a]; - }); - Object.keys(schema.objectclasses).forEach(function(oc) { - objectclasses[oc] = schema.objectclasses[oc]; - }); - - if (++finished === files.length) { - if (cb) { - schema = compile(attributes, objectclasses); - return cb(null, schema); - } - } - }); - }); - }); -} - - - -///--- Exported API - -module.exports = { - - load: load, - parse: parse, - parseFile: parseFile - - -}; - diff --git a/lib/schema/search_handler.js b/lib/schema/search_handler.js deleted file mode 100644 index 8b286e6..0000000 --- a/lib/schema/search_handler.js +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2011 Mark Cavage, Inc. All rights reserved. - -var assert = require('assert'); - -var dn = require('../dn'); -var errors = require('../errors'); -var logStub = require('../log_stub'); - -var getTransformer = require('./transform').getTransformer; - - -function transformFilter(schema, filter) { - assert.ok(schema); - assert.ok(filter); - - var attributes = schema.attributes; - - switch (filter.type) { - case 'equal': - case 'approx': - case 'ge': - case 'le': - if (!attributes[filter.attribute.toLowerCase()]) - throw new errors.NoSuchAttributeError(filter.attribute); - - var transform = getTransformer(schema, filter.attribute); - if (transform) - filter.value = transform(filter.value) || filter.value; - - break; - - case 'substring': - case 'present': - if (!attributes[filter.attribute.toLowerCase()]) - throw new errors.NoSuchAttributeError(filter.attribute); - - break; - - case 'and': - case 'or': - for (var i = 0; i < filter.filters.length; i++) - filter.filters[i] = transformFilter(schema, filter.filters[i]); - - break; - - case 'not': - filter.filter = trasnformFilter(schema, filter.filter); - } - - return filter; -} - - - -function createSearchHandler(options) { - if (!options || typeof(options) !== 'object') - throw new TypeError('options (object) required'); - if (!options.schema || typeof(options.schema) !== 'object') - throw new TypeError('options.schema (object) required'); - - var log4js = options.log4js || logStub; - var log = log4js.getLogger('SchemaSearchHandler'); - var schema = options.schema; - - var CVErr = errors.ConstraintViolationError; - var NSAErr = errors.NoSuchAttributeError; - var OCVErr = errors.ObjectclassViolationError; - - return function schemaSearchHandler(req, res, next) { - if (log.isDebugEnabled()) - log.debug('%s running %j against schema', req.logId, req.filter); - - try { - req.filter = transformFilter(schema, req.filter); - } catch (e) { - if (log.isDebugEnabled()) - log.debug('%s error transforming filter: %s', req.logId, e.stack); - return next(e); - } - - return next(); - } -} - - - -module.exports = createSearchHandler; diff --git a/lib/schema/transform.js b/lib/schema/transform.js deleted file mode 100644 index 2e24b5e..0000000 --- a/lib/schema/transform.js +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2011 Mark Cavage, Inc. All rights reserved. - -var assert = require('assert'); - -var dn = require('../dn'); - - - -///--- API - -function _getTransformer(syntax) { - assert.ok(syntax); - - // TODO size enforcement - if (/\}$/.test(syntax)) - syntax = syntax.replace(/\{.+\}$/, ''); - - switch (syntax) { - case '1.3.6.1.4.1.1466.115.121.1.27': // int - case '1.3.6.1.4.1.1466.115.121.1.36': // numeric string - return function(value) { - return parseInt(value, 10); - }; - - case '1.3.6.1.4.1.1466.115.121.1.7': // boolean - return function(value) { - return /^true$/i.test(value); - }; - - case '1.3.6.1.4.1.1466.115.121.1.5': // binary - return function(value) { - return new Buffer(value).toString('base64'); - }; - - case '1.3.6.1.4.1.1466.115.121.1.12': // dn syntax - return function(value) { - return dn.parse(value).toString(); - }; - default: - // noop - } - - return null; - -} - - -function getTransformer(schema, type) { - assert.ok(schema); - assert.ok(type); - - if (!schema.attributes[type] || !schema.attributes[type].syntax) - return null; - - return _getTransformer(schema.attributes[type].syntax); -} - - -function transformValue(schema, type, value) { - assert.ok(schema); - assert.ok(type); - assert.ok(value); - - if (!schema.attributes[type] || !schema.attributes[type].syntax) - return value; - - var transformer = _getTransformer(schema.attributes[type].syntax); - - return transformer ? transformer(value) : null; -} - - -function transformObject(schema, attributes, keys) { - assert.ok(schema); - assert.ok(attributes); - - if (!keys) - keys = Object.keys(attributes); - - var xformed = false; - - keys.forEach(function(k) { - k = k.toLowerCase(); - - var transform = _getTransformer(schema.attributes[k].syntax); - if (transform) { - xformed = true; - - var vals = attributes[k]; - console.log('%s -> %j', k, vals); - for (var i = 0; i < vals.length; i++) - vals[i] = transform(vals[i]); - } - }); - - return xformed; -} - - - - -module.exports = { - - transformObject: transformObject, - transformValue: transformValue, - getTransformer: getTransformer -}; - - - - // var syntax = schema.attributes[k].syntax; - // if (/\}$/.test(syntax)) - // syntax = syntax.replace(/\{.+\}$/, ''); - - // switch (syntax) { - // case '1.3.6.1.4.1.1466.115.121.1.27': // int - // case '1.3.6.1.4.1.1466.115.121.1.36': // numeric string - // for (j = 0; j < attr.length; j++) - // attr[j] = parseInt(attr[j], 10); - // xformed = true; - // break; - // case '1.3.6.1.4.1.1466.115.121.1.7': // boolean - // for (j = 0; j < attr.length; j++) - // attr[j] = /^true$/i.test(attr[j]); - // xformed = true; - // break; - // case '1.3.6.1.4.1.1466.115.121.1.5': // binary - // for (j = 0; j < attr.length; j++) - // attr[j] = new Buffer(attr[j]).toString('base64'); - // xformed = true; - // break; - // case '1.3.6.1.4.1.1466.115.121.1.12': // dn syntax - // for (j = 0; j < attr.length; j++) - // attr[j] = dn.parse(attr[j]).toString(); - // xformed = true; - // break; - // default: - // // noop - // } diff --git a/lib/server.js b/lib/server.js index 54fe285..a6f5312 100644 --- a/lib/server.js +++ b/lib/server.js @@ -7,7 +7,6 @@ var tls = require('tls'); var util = require('util'); var asn1 = require('asn1'); -var sprintf = require('sprintf').sprintf; var dn = require('./dn'); var dtrace = require('./dtrace'); @@ -37,6 +36,8 @@ var Ber = asn1.Ber; var BerReader = asn1.BerReader; var DN = dn.DN; +var sprintf = util.format; + ///--- Helpers @@ -55,14 +56,14 @@ function mergeFunctionArgs(argv, start, end) { var arr = argv[i]; for (var j = 0; j < arr.length; j++) { if (!(arr[j] instanceof Function)) { - throw new TypeError('Invalid argument type: ' + typeof(arr[j])); + throw new TypeError('Invalid argument type: ' + typeof (arr[j])); } handlers.push(arr[j]); } } else if (argv[i] instanceof Function) { handlers.push(argv[i]); } else { - throw new TypeError('Invalid argument type: ' + typeof(argv[i])); + throw new TypeError('Invalid argument type: ' + typeof (argv[i])); } } @@ -220,10 +221,12 @@ function fireDTraceProbe(req, res) { case Protocol.LDAP_REQ_UNBIND: op = 'unbind'; break; + default: + break; } res._dtraceOp = op; - dtrace.fire('server-' + op + '-start', function() { + dtrace.fire('server-' + op + '-start', function () { return probeArgs; }); } @@ -249,15 +252,15 @@ function fireDTraceProbe(req, res) { */ function Server(options) { if (options) { - if (typeof(options) !== 'object') + if (typeof (options) !== 'object') throw new TypeError('options (object) required'); - if (options.log4js && typeof(options.log4js) !== 'object') + if (options.log4js && typeof (options.log4js) !== 'object') throw new TypeError('options.log4s must be an object'); if (options.certificate || options.key) { if (!(options.certificate && options.key) || - typeof(options.certificate) !== 'string' || - typeof(options.key) !== 'string') { + typeof (options.certificate) !== 'string' || + typeof (options.key) !== 'string') { throw new TypeError('options.certificate and options.key (string) ' + 'are both required for TLS'); } @@ -296,26 +299,26 @@ function Server(options) { config: options, _bindDN: new DN([rdn]) }; - c.addListener('timeout', function() { + c.addListener('timeout', function () { log.trace('%s timed out', c.ldap.id); c.destroy(); }); - c.addListener('end', function() { + c.addListener('end', function () { log.trace('%s shutdown', c.ldap.id); }); - c.addListener('error', function(err) { + c.addListener('error', function (err) { log.warn('%s unexpected connection error', c.ldap.id, err); c.destroy(); }); - c.addListener('close', function(had_err) { + c.addListener('close', function (had_err) { log.trace('%s close; had_err=%j', c.ldap.id, had_err); c.end(); }); - c.ldap.__defineGetter__('bindDN', function() { + c.ldap.__defineGetter__('bindDN', function () { return c.ldap._bindDN; }); - c.ldap.__defineSetter__('bindDN', function(val) { + c.ldap.__defineSetter__('bindDN', function (val) { if (!(val instanceof DN)) throw new TypeError('DN required'); @@ -330,14 +333,14 @@ function Server(options) { if (log.isTraceEnabled()) log.trace('new connection from %s', c.ldap.id); - dtrace.fire('server-connection', function() { + dtrace.fire('server-connection', function () { return [c.remoteAddress]; }); c.parser = new Parser({ log4js: options.log4js }); - c.parser.on('message', function(req) { + c.parser.on('message', function (req) { req.connection = c; req.logId = c.ldap.id + '::' + req.messageID; req.startTime = new Date().getTime(); @@ -359,7 +362,7 @@ function Server(options) { var chain = self._getHandlerChain(req, res); var i = 0; - return function(err) { + return function (err) { function sendError(err) { res.status = err.code || errors.LDAP_OPERATIONS_ERROR; res.matchedDN = req.suffix ? req.suffix.toString() : ''; @@ -373,7 +376,7 @@ function Server(options) { function next() {} // stub out next for the post chain - self._postChain.forEach(function(c) { + self._postChain.forEach(function (c) { c.call(self, req, res, next); }); } @@ -403,7 +406,7 @@ function Server(options) { }(); }); - c.parser.on('error', function(err, message) { + c.parser.on('error', function (err, message) { log.error('Exception happened parsing for %s: %s', c.ldap.id, err.stack); @@ -420,7 +423,7 @@ function Server(options) { return c.end(res.toBer()); }); - c.on('data', function(data) { + c.on('data', function (data) { if (log.isTraceEnabled()) log.trace('data on %s: %s', c.ldap.id, util.inspect(data)); @@ -436,7 +439,7 @@ function Server(options) { } }); - }; // end newConnection + } // end newConnection this.routes = {}; if ((options.cert || options.certificate) && options.key) { @@ -449,26 +452,26 @@ function Server(options) { this.server.ldap = { config: options }; - this.server.on('close', function() { + this.server.on('close', function () { self.emit('close'); }); - this.server.on('error', function(err) { + this.server.on('error', function (err) { self.emit('error', err); }); - this.__defineGetter__('maxConnections', function() { + this.__defineGetter__('maxConnections', function () { return self.server.maxConnections; }); - this.__defineSetter__('maxConnections', function(val) { + this.__defineSetter__('maxConnections', function (val) { self.server.maxConnections = val; }); - this.__defineGetter__('connections', function() { + this.__defineGetter__('connections', function () { return self.server.connections; }); - this.__defineGetter__('name', function() { + this.__defineGetter__('name', function () { return 'LDAPServer'; }); - this.__defineGetter__('url', function() { + this.__defineGetter__('url', function () { var str; if (this.server instanceof tls.Server) { str = 'ldaps://'; @@ -495,7 +498,7 @@ module.exports = Server; * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.add = function(name) { +Server.prototype.add = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_ADD, name, args); }; @@ -511,7 +514,7 @@ Server.prototype.add = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.bind = function(name) { +Server.prototype.bind = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_BIND, name, args); }; @@ -527,7 +530,7 @@ Server.prototype.bind = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.compare = function(name) { +Server.prototype.compare = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_COMPARE, name, args); }; @@ -543,7 +546,7 @@ Server.prototype.compare = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.del = function(name) { +Server.prototype.del = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_DELETE, name, args); }; @@ -559,7 +562,7 @@ Server.prototype.del = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input. */ -Server.prototype.exop = function(name) { +Server.prototype.exop = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_EXTENSION, name, args, true); }; @@ -575,7 +578,7 @@ Server.prototype.exop = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.modify = function(name) { +Server.prototype.modify = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_MODIFY, name, args); }; @@ -591,7 +594,7 @@ Server.prototype.modify = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.modifyDN = function(name) { +Server.prototype.modifyDN = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_MODRDN, name, args); }; @@ -607,7 +610,7 @@ Server.prototype.modifyDN = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.search = function(name) { +Server.prototype.search = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_SEARCH, name, args); }; @@ -622,7 +625,7 @@ Server.prototype.search = function(name) { * @return {Server} this so you can chain calls. * @throws {TypeError} on bad input */ -Server.prototype.unbind = function() { +Server.prototype.unbind = function () { var args = Array.prototype.slice.call(arguments, 0); return this._mount(Protocol.LDAP_REQ_UNBIND, 'unbind', args, true); }; @@ -632,36 +635,36 @@ Server.prototype.use = function use() { var args = Array.prototype.slice.call(arguments); var chain = mergeFunctionArgs(args, 0, args.length); var self = this; - chain.forEach(function(c) { + chain.forEach(function (c) { self._chain.push(c); }); }; -Server.prototype.after = function() { +Server.prototype.after = function () { if (!this._postChain) this._postChain = []; var self = this; - mergeFunctionArgs(arguments).forEach(function(h) { + mergeFunctionArgs(arguments).forEach(function (h) { self._postChain.push(h); }); }; // All these just reexpose the requisite net.Server APIs -Server.prototype.listen = function(port, host, callback) { +Server.prototype.listen = function (port, host, callback) { if (!port) throw new TypeError('port (number) required'); - if (typeof(host) === 'function') { + if (typeof (host) === 'function') { callback = host; host = '0.0.0.0'; } var self = this; function _callback() { - if (typeof(port) === 'number') { + if (typeof (port) === 'number') { self.host = host; self.port = port; } else { @@ -669,30 +672,30 @@ Server.prototype.listen = function(port, host, callback) { self.port = self.server.fd; } - if (typeof(callback) === 'function') + if (typeof (callback) === 'function') callback(); } - if (typeof(port) === 'number') { + if (typeof (port) === 'number') { return this.server.listen(port, host, _callback); } else { return this.server.listen(port, _callback); } }; -Server.prototype.listenFD = function(fd) { +Server.prototype.listenFD = function (fd) { this.host = 'unix-domain-socket'; this.port = fd; return this.server.listenFD(fd); }; -Server.prototype.close = function() { +Server.prototype.close = function () { return this.server.close(); }; -Server.prototype.address = function() { +Server.prototype.address = function () { return this.server.address(); }; -Server.prototype._getRoute = function(_dn, backend) { +Server.prototype._getRoute = function (_dn, backend) { assert.ok(dn); if (!backend) @@ -715,7 +718,7 @@ Server.prototype._getRoute = function(_dn, backend) { }; -Server.prototype._getHandlerChain = function(req, res) { +Server.prototype._getHandlerChain = function _getHandlerChain(req, res) { assert.ok(req); fireDTraceProbe(req, res); @@ -741,49 +744,42 @@ Server.prototype._getHandlerChain = function(req, res) { // Special cases are abandons, exops and unbinds, handle those first. if (req.protocolOp === Protocol.LDAP_REQ_EXTENSION) { - if (r !== req.requestName) - continue; - - return { - backend: routes.backend, - handlers: route[op] || [noExOpHandler] - }; - } else if (req.protocolOp === Protocol.LDAP_REQ_UNBIND) { - function getUnbindChain() { - if (routes['unbind'] && routes['unbind'][op]) - return routes['unbind'][op]; - - self.log.debug('%s unbind request %j', req.logId, req.json); - return [defaultNoOpHandler]; + if (r === req.requestName) { + return { + backend: routes.backend, + handlers: route[op] || [noExOpHandler] + }; } - + } else if (req.protocolOp === Protocol.LDAP_REQ_UNBIND) { return { backend: routes['unbind'] ? routes['unbind'].backend : self, - handlers: getUnbindChain() + handlers: function getUnbindChain() { + if (routes['unbind'] && routes['unbind'][op]) + return routes['unbind'][op]; + + self.log.debug('%s unbind request %j', req.logId, req.json); + return [defaultNoOpHandler]; + } }; } else if (req.protocolOp === Protocol.LDAP_REQ_ABANDON) { return { backend: self, handlers: [defaultNoOpHandler] }; + } else if (route[op]) { + // Otherwise, match via DN rules + assert.ok(req.dn); + assert.ok(route.dn); + + if (route.dn.equals(req.dn) || route.dn.parentOf(req.dn)) { + // We should be good to go. + req.suffix = route.dn; + return { + backend: route.backend, + handlers: route[op] || [defaultHandler] + }; + } } - - if (!route[op]) - continue; - - // Otherwise, match via DN rules - assert.ok(req.dn); - assert.ok(route.dn); - - if (!route.dn.equals(req.dn) && !route.dn.parentOf(req.dn)) - continue; - - // We should be good to go. - req.suffix = route.dn; - return { - backend: route.backend, - handlers: route[op] || [defaultHandler] - }; } // We're here, so nothing matched. @@ -795,12 +791,12 @@ Server.prototype._getHandlerChain = function(req, res) { }; -Server.prototype._mount = function(op, name, argv, notDN) { +Server.prototype._mount = function (op, name, argv, notDN) { assert.ok(op); assert.ok(name !== undefined); assert.ok(argv); - if (typeof(name) !== 'string') + if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (!argv.length) throw new Error('at least one handler required'); @@ -808,14 +804,14 @@ Server.prototype._mount = function(op, name, argv, notDN) { var backend = this; var index = 0; - if (typeof(argv[0]) === 'object' && !Array.isArray(argv[0])) { + if (typeof (argv[0]) === 'object' && !Array.isArray(argv[0])) { backend = argv[0]; index = 1; } var route = this._getRoute(notDN ? name : dn.parse(name), backend); var chain = this._chain.slice(); - argv.slice(index).forEach(function(a) { + argv.slice(index).forEach(function (a) { chain.push(a); }); route['0x' + op.toString(16)] = mergeFunctionArgs(chain); diff --git a/lib/url.js b/lib/url.js index 6e391f1..f9be5e4 100644 --- a/lib/url.js +++ b/lib/url.js @@ -10,7 +10,7 @@ var dn = require('./dn'); module.exports = { - parse: function(urlStr, parseDN) { + parse: function (urlStr, parseDN) { var u = url.parse(urlStr); if (!u.protocol || !(u.protocol === 'ldap:' || u.protocol === 'ldaps:')) throw new TypeError(urlStr + ' is an invalid LDAP url (protocol)'); @@ -36,7 +36,7 @@ module.exports = { var tmp = u.search.substr(1).split('?'); if (tmp && tmp.length) { if (tmp[0]) { - tmp[0].split(',').forEach(function(a) { + tmp[0].split(',').forEach(function (a) { u.attributes.push(querystring.unescape(a.trim())); }); } diff --git a/package.json b/package.json index 3a85702..632c244 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "ldapjs", "homepage": "http://ldapjs.org", "description": "LDAP client and server APIs", - "version": "0.4.8", + "version": "0.5.0", "repository": { "type": "git", "url": "git://github.com/mcavage/node-ldapjs.git" @@ -20,17 +20,17 @@ "lib": "./lib" }, "engines": { - "node": ">=0.4" + "node": ">=0.6" }, "dependencies": { "asn1": "0.1.11", - "buffertools": "1.0.6", - "dtrace-provider": "0.0.3", - "nopt": "1.0.10", - "sprintf": "0.1.1" + "buffertools": "1.0.7", + "bunyan": "0.6.3", + "dtrace-provider": "0.0.6", + "nopt": "1.0.10" }, "devDependencies": { - "tap": "0.1.4", + "tap": "0.2", "node-uuid": "1.3.3" }, "scripts": { diff --git a/tst/attribute.test.js b/test/attribute.test.js similarity index 89% rename from tst/attribute.test.js rename to test/attribute.test.js index bac12fa..c97e8e7 100644 --- a/tst/attribute.test.js +++ b/test/attribute.test.js @@ -14,20 +14,20 @@ var Attribute; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { Attribute = require('../lib/index').Attribute; t.ok(Attribute); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new Attribute()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var attr = new Attribute({ type: 'cn', vals: ['foo', 'bar'] @@ -43,7 +43,7 @@ test('new with args', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var attr = new Attribute({ type: 'cn', vals: ['foo', 'bar'] @@ -61,7 +61,7 @@ test('toBer', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.startSequence(); ber.writeString('cn'); diff --git a/tst/change.test.js b/test/change.test.js similarity index 88% rename from tst/change.test.js rename to test/change.test.js index b2ec8be..b9b3b81 100644 --- a/tst/change.test.js +++ b/test/change.test.js @@ -15,7 +15,7 @@ var Change; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { Attribute = require('../lib/index').Attribute; Change = require('../lib/index').Change; t.ok(Attribute); @@ -24,13 +24,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new Change()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var change = new Change({ operation: 0x00, modification: new Attribute({ @@ -50,16 +50,15 @@ test('new with args', function(t) { }); -test('GH-31 (multiple attributes per Change)', function(t) { +test('GH-31 (multiple attributes per Change)', function (t) { try { - new Change({ + t.notOk(new Change({ operation: 'replace', modification: { cn: 'foo', sn: 'bar' } - }); - t.fail('should have thrown'); + }), 'should have thrown'); } catch (e) { t.ok(e); t.end(); @@ -67,7 +66,7 @@ test('GH-31 (multiple attributes per Change)', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var change = new Change({ operation: 'Add', modification: new Attribute({ @@ -91,7 +90,7 @@ test('toBer', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.startSequence(); ber.writeEnumeration(0x00); diff --git a/tst/client.test.js b/test/client.test.js similarity index 70% rename from tst/client.test.js rename to test/client.test.js index 84cbec2..3f7e622 100644 --- a/tst/client.test.js +++ b/test/client.test.js @@ -21,7 +21,7 @@ var server; ///--- Tests -test('setup', function(t) { +test('setup', function (t) { ldap = require('../lib/index'); t.ok(ldap); t.ok(ldap.createClient); @@ -35,7 +35,7 @@ test('setup', function(t) { server = ldap.createServer(); t.ok(server); - server.bind(BIND_DN, function(req, res, next) { + server.bind(BIND_DN, function (req, res, next) { if (req.credentials !== BIND_PW) return next(new ldap.InvalidCredentialsError('Invalid password')); @@ -43,43 +43,43 @@ test('setup', function(t) { return next(); }); - server.add(SUFFIX, function(req, res, next) { + server.add(SUFFIX, function (req, res, next) { res.end(); return next(); }); - server.compare(SUFFIX, function(req, res, next) { + server.compare(SUFFIX, function (req, res, next) { res.end(req.value === 'test'); return next(); }); - server.del(SUFFIX, function(req, res, next) { + server.del(SUFFIX, function (req, res, next) { res.end(); return next(); }); // LDAP whoami - server.exop('1.3.6.1.4.1.4203.1.11.3', function(req, res, next) { + server.exop('1.3.6.1.4.1.4203.1.11.3', function (req, res, next) { res.value = 'u:xxyyz@EXAMPLE.NET'; res.end(); return next(); }); - server.modify(SUFFIX, function(req, res, next) { + server.modify(SUFFIX, function (req, res, next) { res.end(); return next(); }); - server.modifyDN(SUFFIX, function(req, res, next) { + server.modifyDN(SUFFIX, function (req, res, next) { res.end(); return next(); }); - server.search('dc=timeout', function(req, res, next) { + server.search('dc=timeout', function (req, res, next) { // Haha client! }); - server.search(SUFFIX, function(req, res, next) { + server.search(SUFFIX, function (req, res, next) { if (req.dn.equals('cn=ref,' + SUFFIX)) { res.send(res.createSearchReference('ldap://localhost')); @@ -109,7 +109,7 @@ test('setup', function(t) { return next(); }); - server.search('dc=empty', function(req, res, next) { + server.search('dc=empty', function (req, res, next) { res.send({ dn: 'dc=empty', attributes: { @@ -121,12 +121,12 @@ test('setup', function(t) { return next(); }); - server.unbind(function(req, res, next) { + server.unbind(function (req, res, next) { res.end(); return next(); }); - server.listen(SOCKET, function() { + server.listen(SOCKET, function () { client = ldap.createClient({ socketPath: SOCKET, reconnect: false // turn this off for unit testing @@ -140,8 +140,8 @@ test('setup', function(t) { }); -test('simple bind success', function(t) { - client.bind(BIND_DN, BIND_PW, function(err, res) { +test('simple bind success', function (t) { + client.bind(BIND_DN, BIND_PW, function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -150,8 +150,8 @@ test('simple bind success', function(t) { }); -test('simple bind failure', function(t) { - client.bind(BIND_DN, uuid(), function(err, res) { +test('simple bind failure', function (t) { + client.bind(BIND_DN, uuid(), function (err, res) { t.ok(err); t.notOk(res); @@ -166,14 +166,14 @@ test('simple bind failure', function(t) { }); -test('add success', function(t) { +test('add success', function (t) { var attrs = [ new Attribute({ type: 'cn', vals: ['test'] }) ]; - client.add('cn=add, ' + SUFFIX, attrs, function(err, res) { + client.add('cn=add, ' + SUFFIX, attrs, function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -182,12 +182,12 @@ test('add success', function(t) { }); -test('add success with object', function(t) { +test('add success with object', function (t) { var entry = { cn: ['unit', 'add'], sn: 'test' }; - client.add('cn=add, ' + SUFFIX, entry, function(err, res) { + client.add('cn=add, ' + SUFFIX, entry, function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -196,8 +196,8 @@ test('add success with object', function(t) { }); -test('compare success', function(t) { - client.compare('cn=compare, ' + SUFFIX, 'cn', 'test', function(err, +test('compare success', function (t) { + client.compare('cn=compare, ' + SUFFIX, 'cn', 'test', function (err, matched, res) { t.ifError(err); @@ -208,8 +208,8 @@ test('compare success', function(t) { }); -test('compare false', function(t) { - client.compare('cn=compare, ' + SUFFIX, 'cn', 'foo', function(err, +test('compare false', function (t) { + client.compare('cn=compare, ' + SUFFIX, 'cn', 'foo', function (err, matched, res) { t.ifError(err); @@ -220,8 +220,8 @@ test('compare false', function(t) { }); -test('compare bad suffix', function(t) { - client.compare('cn=' + uuid(), 'cn', 'foo', function(err, +test('compare bad suffix', function (t) { + client.compare('cn=' + uuid(), 'cn', 'foo', function (err, matched, res) { t.ok(err); @@ -233,8 +233,8 @@ test('compare bad suffix', function(t) { }); -test('delete success', function(t) { - client.del('cn=delete, ' + SUFFIX, function(err, res) { +test('delete success', function (t) { + client.del('cn=delete, ' + SUFFIX, function (err, res) { t.ifError(err); t.ok(res); t.end(); @@ -242,8 +242,8 @@ test('delete success', function(t) { }); -test('exop success', function(t) { - client.exop('1.3.6.1.4.1.4203.1.11.3', function(err, value, res) { +test('exop success', function (t) { + client.exop('1.3.6.1.4.1.4203.1.11.3', function (err, value, res) { t.ifError(err); t.ok(value); t.ok(res); @@ -253,8 +253,8 @@ test('exop success', function(t) { }); -test('exop invalid', function(t) { - client.exop('1.2.3.4', function(err, res) { +test('exop invalid', function (t) { + client.exop('1.2.3.4', function (err, res) { t.ok(err); t.ok(err instanceof ldap.ProtocolError); t.notOk(res); @@ -263,15 +263,15 @@ test('exop invalid', function(t) { }); -test('bogus exop (GH-17)', function(t) { - client.exop('cn=root', function(err, value) { +test('bogus exop (GH-17)', function (t) { + client.exop('cn=root', function (err, value) { t.ok(err); t.end(); }); }); -test('modify success', function(t) { +test('modify success', function (t) { var change = new Change({ type: 'Replace', modification: new Attribute({ @@ -279,7 +279,7 @@ test('modify success', function(t) { vals: ['test'] }) }); - client.modify('cn=modify, ' + SUFFIX, change, function(err, res) { + client.modify('cn=modify, ' + SUFFIX, change, function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -288,14 +288,14 @@ test('modify success', function(t) { }); -test('modify change plain object success', function(t) { +test('modify change plain object success', function (t) { var change = new Change({ type: 'Replace', modification: { cn: 'test' } }); - client.modify('cn=modify, ' + SUFFIX, change, function(err, res) { + client.modify('cn=modify, ' + SUFFIX, change, function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -304,7 +304,7 @@ test('modify change plain object success', function(t) { }); -test('modify array success', function(t) { +test('modify array success', function (t) { var changes = [ new Change({ operation: 'Replace', @@ -320,7 +320,7 @@ test('modify array success', function(t) { }) }) ]; - client.modify('cn=modify, ' + SUFFIX, changes, function(err, res) { + client.modify('cn=modify, ' + SUFFIX, changes, function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -329,7 +329,7 @@ test('modify array success', function(t) { }); -test('modify change plain object success (GH-31)', function(t) { +test('modify change plain object success (GH-31)', function (t) { var change = { type: 'replace', modification: { @@ -337,7 +337,7 @@ test('modify change plain object success (GH-31)', function(t) { sn: 'bar' } }; - client.modify('cn=modify, ' + SUFFIX, change, function(err, res) { + client.modify('cn=modify, ' + SUFFIX, change, function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -346,8 +346,8 @@ test('modify change plain object success (GH-31)', function(t) { }); -test('modify DN new RDN only', function(t) { - client.modifyDN('cn=old, ' + SUFFIX, 'cn=new', function(err, res) { +test('modify DN new RDN only', function (t) { + client.modifyDN('cn=old, ' + SUFFIX, 'cn=new', function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -356,8 +356,8 @@ test('modify DN new RDN only', function(t) { }); -test('modify DN new superior', function(t) { - client.modifyDN('cn=old, ' + SUFFIX, 'cn=new, dc=foo', function(err, res) { +test('modify DN new superior', function (t) { + client.modifyDN('cn=old, ' + SUFFIX, 'cn=new, dc=foo', function (err, res) { t.ifError(err); t.ok(res); t.equal(res.status, 0); @@ -366,12 +366,12 @@ test('modify DN new superior', function(t) { }); -test('search basic', function(t) { - client.search('cn=test, ' + SUFFIX, '(objectclass=*)', function(err, res) { +test('search basic', function (t) { + client.search('cn=test, ' + SUFFIX, '(objectclass=*)', function (err, res) { t.ifError(err); t.ok(res); var gotEntry = 0; - res.on('searchEntry', function(entry) { + res.on('searchEntry', function (entry) { t.ok(entry); t.ok(entry instanceof ldap.SearchEntry); t.equal(entry.dn.toString(), 'cn=test, ' + SUFFIX); @@ -382,10 +382,10 @@ test('search basic', function(t) { t.ok(entry.object); gotEntry++; }); - res.on('error', function(err) { + res.on('error', function (err) { t.fail(err); }); - res.on('end', function(res) { + res.on('end', function (res) { t.ok(res); t.ok(res instanceof ldap.SearchResponse); t.equal(res.status, 0); @@ -396,26 +396,26 @@ test('search basic', function(t) { }); -test('search referral', function(t) { - client.search('cn=ref, ' + SUFFIX, '(objectclass=*)', function(err, res) { +test('search referral', function (t) { + client.search('cn=ref, ' + SUFFIX, '(objectclass=*)', function (err, res) { t.ifError(err); t.ok(res); var gotEntry = 0; var gotReferral = false; - res.on('searchEntry', function(entry) { + res.on('searchEntry', function (entry) { gotEntry++; }); - res.on('searchReference', function(referral) { + res.on('searchReference', function (referral) { gotReferral = true; t.ok(referral); t.ok(referral instanceof ldap.SearchReference); t.ok(referral.uris); t.ok(referral.uris.length); }); - res.on('error', function(err) { + res.on('error', function (err) { t.fail(err); }); - res.on('end', function(res) { + res.on('end', function (res) { t.ok(res); t.ok(res instanceof ldap.SearchResponse); t.equal(res.status, 0); @@ -427,12 +427,12 @@ test('search referral', function(t) { }); -test('search empty attribute', function(t) { - client.search('dc=empty', '(objectclass=*)', function(err, res) { +test('search empty attribute', function (t) { + client.search('dc=empty', '(objectclass=*)', function (err, res) { t.ifError(err); t.ok(res); var gotEntry = 0; - res.on('searchEntry', function(entry) { + res.on('searchEntry', function (entry) { var obj = entry.toObject(); t.equal('dc=empty', obj.dn); t.ok(obj.member); @@ -441,10 +441,10 @@ test('search empty attribute', function(t) { t.ok(obj['member;range=0-1'].length); gotEntry++; }); - res.on('error', function(err) { + res.on('error', function (err) { t.fail(err); }); - res.on('end', function(res) { + res.on('end', function (res) { t.ok(res); t.ok(res instanceof ldap.SearchResponse); t.equal(res.status, 0); @@ -455,14 +455,14 @@ test('search empty attribute', function(t) { }); -test('GH-21 binary attributes', function(t) { - client.search('cn=bin, ' + SUFFIX, '(objectclass=*)', function(err, res) { +test('GH-21 binary attributes', function (t) { + client.search('cn=bin, ' + SUFFIX, '(objectclass=*)', function (err, res) { t.ifError(err); t.ok(res); var gotEntry = 0; var expect = new Buffer('\u00bd + \u00bc = \u00be', 'utf8'); var expect2 = new Buffer([0xB5, 0xE7, 0xCA, 0xD3, 0xBB, 0xFA]); - res.on('searchEntry', function(entry) { + res.on('searchEntry', function (entry) { t.ok(entry); t.ok(entry instanceof ldap.SearchEntry); t.equal(entry.dn.toString(), 'cn=bin, ' + SUFFIX); @@ -482,10 +482,10 @@ test('GH-21 binary attributes', function(t) { t.ok(entry.object); gotEntry++; }); - res.on('error', function(err) { + res.on('error', function (err) { t.fail(err); }); - res.on('end', function(res) { + res.on('end', function (res) { t.ok(res); t.ok(res instanceof ldap.SearchResponse); t.equal(res.status, 0); @@ -496,16 +496,16 @@ test('GH-21 binary attributes', function(t) { }); -test('GH-23 case insensitive attribute filtering', function(t) { +test('GH-23 case insensitive attribute filtering', function (t) { var opts = { filter: '(objectclass=*)', attributes: ['Cn'] }; - client.search('cn=test, ' + SUFFIX, opts, function(err, res) { + client.search('cn=test, ' + SUFFIX, opts, function (err, res) { t.ifError(err); t.ok(res); var gotEntry = 0; - res.on('searchEntry', function(entry) { + res.on('searchEntry', function (entry) { t.ok(entry); t.ok(entry instanceof ldap.SearchEntry); t.equal(entry.dn.toString(), 'cn=test, ' + SUFFIX); @@ -515,10 +515,10 @@ test('GH-23 case insensitive attribute filtering', function(t) { t.ok(entry.object); gotEntry++; }); - res.on('error', function(err) { + res.on('error', function (err) { t.fail(err); }); - res.on('end', function(res) { + res.on('end', function (res) { t.ok(res); t.ok(res instanceof ldap.SearchResponse); t.equal(res.status, 0); @@ -529,16 +529,16 @@ test('GH-23 case insensitive attribute filtering', function(t) { }); -test('GH-24 attribute selection of *', function(t) { +test('GH-24 attribute selection of *', function (t) { var opts = { filter: '(objectclass=*)', attributes: ['*'] }; - client.search('cn=test, ' + SUFFIX, opts, function(err, res) { + client.search('cn=test, ' + SUFFIX, opts, function (err, res) { t.ifError(err); t.ok(res); var gotEntry = 0; - res.on('searchEntry', function(entry) { + res.on('searchEntry', function (entry) { t.ok(entry); t.ok(entry instanceof ldap.SearchEntry); t.equal(entry.dn.toString(), 'cn=test, ' + SUFFIX); @@ -549,10 +549,10 @@ test('GH-24 attribute selection of *', function(t) { t.ok(entry.object); gotEntry++; }); - res.on('error', function(err) { + res.on('error', function (err) { t.fail(err); }); - res.on('end', function(res) { + res.on('end', function (res) { t.ok(res); t.ok(res instanceof ldap.SearchResponse); t.equal(res.status, 0); @@ -563,34 +563,34 @@ test('GH-24 attribute selection of *', function(t) { }); -test('abandon (GH-27)', function(t) { - client.abandon(401876543, function(err) { +test('abandon (GH-27)', function (t) { + client.abandon(401876543, function (err) { t.ifError(err); t.end(); }); }); -test('unbind (GH-30)', function(t) { - client.unbind(function(err) { +test('unbind (GH-30)', function (t) { + client.unbind(function (err) { t.ifError(err); t.end(); }); }); -test('search timeout (GH-51)', function(t) { +test('search timeout (GH-51)', function (t) { client.timeout = 250; - client.search('dc=timeout', 'objectclass=*', function(err, res) { + client.search('dc=timeout', 'objectclass=*', function (err, res) { t.ok(err); t.end(); }); }); -test('shutdown', function(t) { - client.unbind(function(err) { - server.on('close', function() { +test('shutdown', function (t) { + client.unbind(function (err) { + server.on('close', function () { t.end(); }); server.close(); diff --git a/tst/controls/control.test.js b/test/controls/control.test.js similarity index 87% rename from tst/controls/control.test.js rename to test/controls/control.test.js index e8d2875..0943f15 100644 --- a/tst/controls/control.test.js +++ b/test/controls/control.test.js @@ -15,7 +15,7 @@ var getControl; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { Control = require('../../lib/index').Control; t.ok(Control); getControl = require('../../lib/index').getControl; @@ -24,13 +24,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new Control()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var c = new Control({ type: '2.16.840.1.113730.3.4.2', criticality: true @@ -42,7 +42,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.startSequence(); ber.writeString('2.16.840.1.113730.3.4.2'); @@ -60,7 +60,7 @@ test('parse', function(t) { }); -test('parse no value', function(t) { +test('parse no value', function (t) { var ber = new BerWriter(); ber.startSequence(); ber.writeString('2.16.840.1.113730.3.4.2'); diff --git a/tst/controls/entry_change_notification_control_test.js b/test/controls/entry_change_notification_control_test.js similarity index 93% rename from tst/controls/entry_change_notification_control_test.js rename to test/controls/entry_change_notification_control_test.js index 5fc1bb5..e9a9965 100644 --- a/tst/controls/entry_change_notification_control_test.js +++ b/test/controls/entry_change_notification_control_test.js @@ -13,7 +13,7 @@ var EntryChangeNotificationControl; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { EntryChangeNotificationControl = require('../../lib').EntryChangeNotificationControl; t.ok(EntryChangeNotificationControl); @@ -23,13 +23,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new EntryChangeNotificationControl()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var c = new EntryChangeNotificationControl({ type: '2.16.840.1.113730.3.4.7', criticality: true, @@ -62,7 +62,7 @@ test('new with args', function(t) { t.end(); }); -test('tober', function(t) { +test('tober', function (t) { var psc = new EntryChangeNotificationControl({ type: '2.16.840.1.113730.3.4.7', criticality: true, diff --git a/tst/controls/persistent_search_control.test.js b/test/controls/persistent_search_control.test.js similarity index 86% rename from tst/controls/persistent_search_control.test.js rename to test/controls/persistent_search_control.test.js index b8833a6..37a7667 100644 --- a/tst/controls/persistent_search_control.test.js +++ b/test/controls/persistent_search_control.test.js @@ -13,7 +13,7 @@ var PersistentSearchControl; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { PersistentSearchControl = require('../../lib').PersistentSearchControl; t.ok(PersistentSearchControl); getControl = require('../../lib').getControl; @@ -22,13 +22,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new PersistentSearchControl()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var c = new PersistentSearchControl({ type: '2.16.840.1.113730.3.4.3', criticality: true, @@ -61,23 +61,13 @@ test('new with args', function(t) { t.end(); }); -test('getControl with args', function(t) { +test('getControl with args', function (t) { var buf = new Buffer([ 0x30, 0x26, 0x04, 0x17, 0x32, 0x2e, 0x31, 0x36, 0x2e, 0x38, 0x34, 0x30, 0x2e, 0x31, 0x2e, 0x31, 0x31, 0x33, 0x37, 0x33, 0x30, 0x2e, 0x33, 0x2e, 0x34, 0x2e, 0x33, 0x04, 0x0b, 0x30, 0x09, 0x02, 0x01, 0x0f, 0x01, 0x01, 0xff, 0x01, 0x01, 0xff]); - var options = { - type: '2.16.840.1.113730.3.4.3', - criticality: false, - value: { - changeTypes: 15, - changesOnly: true, - returnECs: true - } - }; - var ber = new BerReader(buf); var psc = getControl(ber); t.ok(psc); @@ -89,7 +79,7 @@ test('getControl with args', function(t) { t.end(); }); -test('tober', function(t) { +test('tober', function (t) { var psc = new PersistentSearchControl({ type: '2.16.840.1.113730.3.4.3', criticality: true, diff --git a/tst/dn.test.js b/test/dn.test.js similarity index 77% rename from tst/dn.test.js rename to test/dn.test.js index 4eb106d..aa3b243 100644 --- a/tst/dn.test.js +++ b/test/dn.test.js @@ -12,74 +12,74 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { dn = require('../lib/index').dn; t.ok(dn); t.end(); }); -test('parse basic', function(t) { +test('parse basic', function (t) { var DN_STR = 'cn=mark, ou=people, o=joyent'; var name = dn.parse(DN_STR); t.ok(name); t.ok(name.rdns); t.ok(Array.isArray(name.rdns)); t.equal(3, name.rdns.length); - name.rdns.forEach(function(rdn) { - t.equal('object', typeof(rdn)); + name.rdns.forEach(function (rdn) { + t.equal('object', typeof (rdn)); }); t.equal(name.toString(), DN_STR); t.end(); }); -test('parse escaped', function(t) { +test('parse escaped', function (t) { var DN_STR = 'cn=m\\,ark, ou=people, o=joyent'; var name = dn.parse(DN_STR); t.ok(name); t.ok(name.rdns); t.ok(Array.isArray(name.rdns)); t.equal(3, name.rdns.length); - name.rdns.forEach(function(rdn) { - t.equal('object', typeof(rdn)); + name.rdns.forEach(function (rdn) { + t.equal('object', typeof (rdn)); }); t.equal(name.toString(), DN_STR); t.end(); }); -test('parse compound', function(t) { +test('parse compound', function (t) { var DN_STR = 'cn=mark+sn=cavage, ou=people, o=joyent'; var name = dn.parse(DN_STR); t.ok(name); t.ok(name.rdns); t.ok(Array.isArray(name.rdns)); t.equal(3, name.rdns.length); - name.rdns.forEach(function(rdn) { - t.equal('object', typeof(rdn)); + name.rdns.forEach(function (rdn) { + t.equal('object', typeof (rdn)); }); t.equal(name.toString(), DN_STR); t.end(); }); -test('parse quoted', function(t) { +test('parse quoted', function (t) { var DN_STR = 'cn="mark+sn=cavage", ou=people, o=joyent'; var name = dn.parse(DN_STR); t.ok(name); t.ok(name.rdns); t.ok(Array.isArray(name.rdns)); t.equal(3, name.rdns.length); - name.rdns.forEach(function(rdn) { - t.equal('object', typeof(rdn)); + name.rdns.forEach(function (rdn) { + t.equal('object', typeof (rdn)); }); t.equal(name.toString(), DN_STR); t.end(); }); -test('equals', function(t) { +test('equals', function (t) { var dn1 = dn.parse('cn=foo, dc=bar'); t.ok(dn1.equals('cn=foo, dc=bar')); t.ok(!dn1.equals('cn=foo1, dc=bar')); @@ -89,7 +89,7 @@ test('equals', function(t) { }); -test('child of', function(t) { +test('child of', function (t) { var dn1 = dn.parse('cn=foo, dc=bar'); t.ok(dn1.childOf('dc=bar')); t.ok(!dn1.childOf('dc=moo')); @@ -101,7 +101,7 @@ test('child of', function(t) { }); -test('parent of', function(t) { +test('parent of', function (t) { var dn1 = dn.parse('cn=foo, dc=bar'); t.ok(dn1.parentOf('cn=moo, cn=foo, dc=bar')); t.ok(!dn1.parentOf('cn=moo, cn=bar, dc=foo')); @@ -112,7 +112,7 @@ test('parent of', function(t) { }); -test('empty DNs GH-16', function(t) { +test('empty DNs GH-16', function (t) { var _dn = dn.parse(''); var _dn2 = dn.parse('cn=foo'); t.notOk(_dn.equals('cn=foo')); @@ -125,7 +125,7 @@ test('empty DNs GH-16', function(t) { }); -test('case insensitive attribute names GH-20', function(t) { +test('case insensitive attribute names GH-20', function (t) { var dn1 = dn.parse('CN=foo, dc=bar'); t.ok(dn1.equals('cn=foo, dc=bar')); t.ok(dn1.equals(dn.parse('cn=foo, DC=bar'))); diff --git a/tst/filters/and.test.js b/test/filters/and.test.js similarity index 87% rename from tst/filters/and.test.js rename to test/filters/and.test.js index ccd6d0c..c7b22c3 100644 --- a/tst/filters/and.test.js +++ b/test/filters/and.test.js @@ -14,7 +14,7 @@ var AndFilter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); EqualityFilter = filters.EqualityFilter; @@ -25,13 +25,13 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { t.ok(new AndFilter()); t.end(); }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new AndFilter(); f.addFilter(new EqualityFilter({ attribute: 'foo', @@ -47,7 +47,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new AndFilter(); f.addFilter(new EqualityFilter({ attribute: 'foo', @@ -63,7 +63,7 @@ test('match true', function(t) { }); -test('match false', function(t) { +test('match false', function (t) { var f = new AndFilter(); f.addFilter(new EqualityFilter({ attribute: 'foo', @@ -77,5 +77,3 @@ test('match false', function(t) { t.ok(!f.matches({ foo: 'bar', zig: 'zonk' })); t.end(); }); - - diff --git a/tst/filters/approx.test.js b/test/filters/approx.test.js similarity index 85% rename from tst/filters/approx.test.js rename to test/filters/approx.test.js index 78cd5f1..d0d66b4 100644 --- a/tst/filters/approx.test.js +++ b/test/filters/approx.test.js @@ -15,7 +15,7 @@ var BerWriter = asn1.BerWriter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); ApproximateFilter = filters.ApproximateFilter; @@ -24,7 +24,7 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { var f = new ApproximateFilter(); t.ok(f); t.ok(!f.attribute); @@ -33,7 +33,7 @@ test('Construct no args', function(t) { }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new ApproximateFilter({ attribute: 'foo', value: 'bar' @@ -46,7 +46,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new ApproximateFilter({ attribute: 'foo', value: 'bar' @@ -57,7 +57,7 @@ test('match true', function(t) { }); -test('match multiple', function(t) { +test('match multiple', function (t) { var f = new ApproximateFilter({ attribute: 'foo', value: 'bar' @@ -68,7 +68,7 @@ test('match multiple', function(t) { t.end(); }); -test('match false', function(t) { +test('match false', function (t) { var f = new ApproximateFilter({ attribute: 'foo', value: 'bar' @@ -79,7 +79,7 @@ test('match false', function(t) { }); -test('parse ok', function(t) { +test('parse ok', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeString('bar'); @@ -92,7 +92,7 @@ test('parse ok', function(t) { }); -test('parse bad', function(t) { +test('parse bad', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeInt(20); diff --git a/tst/filters/eq.test.js b/test/filters/eq.test.js similarity index 85% rename from tst/filters/eq.test.js rename to test/filters/eq.test.js index 0da92f9..454c38f 100644 --- a/tst/filters/eq.test.js +++ b/test/filters/eq.test.js @@ -15,7 +15,7 @@ var BerWriter = asn1.BerWriter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); EqualityFilter = filters.EqualityFilter; @@ -24,7 +24,7 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { var f = new EqualityFilter(); t.ok(f); t.ok(!f.attribute); @@ -33,7 +33,7 @@ test('Construct no args', function(t) { }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new EqualityFilter({ attribute: 'foo', value: 'bar' @@ -46,7 +46,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new EqualityFilter({ attribute: 'foo', value: 'bar' @@ -57,7 +57,7 @@ test('match true', function(t) { }); -test('match multiple', function(t) { +test('match multiple', function (t) { var f = new EqualityFilter({ attribute: 'foo', value: 'bar' @@ -68,7 +68,7 @@ test('match multiple', function(t) { }); -test('match false', function(t) { +test('match false', function (t) { var f = new EqualityFilter({ attribute: 'foo', value: 'bar' @@ -79,7 +79,7 @@ test('match false', function(t) { }); -test('parse ok', function(t) { +test('parse ok', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeString('bar'); @@ -92,7 +92,7 @@ test('parse ok', function(t) { }); -test('parse bad', function(t) { +test('parse bad', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeInt(20); diff --git a/tst/filters/ext.test.js b/test/filters/ext.test.js similarity index 84% rename from tst/filters/ext.test.js rename to test/filters/ext.test.js index 07ae381..a84f1fd 100644 --- a/tst/filters/ext.test.js +++ b/test/filters/ext.test.js @@ -15,7 +15,7 @@ var filters; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { filters = require('../../lib/index').filters; t.ok(filters); ExtensibleFilter = filters.ExtensibleFilter; @@ -24,14 +24,14 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { var f = new ExtensibleFilter(); t.ok(f); t.end(); }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new ExtensibleFilter({ matchType: 'foo', value: 'bar' @@ -44,7 +44,7 @@ test('Construct args', function(t) { }); -test('parse RFC example 1', function(t) { +test('parse RFC example 1', function (t) { var f = filters.parseString('(cn:caseExactMatch:=Fred Flintstone)'); t.ok(f); t.equal(f.matchType, 'cn'); @@ -55,7 +55,7 @@ test('parse RFC example 1', function(t) { }); -test('parse RFC example 2', function(t) { +test('parse RFC example 2', function (t) { var f = filters.parseString('(cn:=Betty Rubble)'); t.ok(f); t.equal(f.matchType, 'cn'); @@ -66,7 +66,7 @@ test('parse RFC example 2', function(t) { }); -test('parse RFC example 3', function(t) { +test('parse RFC example 3', function (t) { var f = filters.parseString('(sn:dn:2.4.6.8.10:=Barney Rubble)'); t.ok(f); t.equal(f.matchType, 'sn'); @@ -77,7 +77,7 @@ test('parse RFC example 3', function(t) { }); -test('parse RFC example 3', function(t) { +test('parse RFC example 3', function (t) { var f = filters.parseString('(o:dn:=Ace Industry)'); t.ok(f); t.equal(f.matchType, 'o'); @@ -88,7 +88,7 @@ test('parse RFC example 3', function(t) { }); -test('parse RFC example 4', function(t) { +test('parse RFC example 4', function (t) { var f = filters.parseString('(:1.2.3:=Wilma Flintstone)'); t.ok(f); t.notOk(f.matchType); @@ -99,7 +99,7 @@ test('parse RFC example 4', function(t) { }); -test('parse RFC example 5', function(t) { +test('parse RFC example 5', function (t) { var f = filters.parseString('(:DN:2.4.6.8.10:=Dino)'); t.ok(f); t.notOk(f.matchType); @@ -108,4 +108,3 @@ test('parse RFC example 5', function(t) { t.ok(f.dnAttributes); t.end(); }); - diff --git a/tst/filters/ge.test.js b/test/filters/ge.test.js similarity index 85% rename from tst/filters/ge.test.js rename to test/filters/ge.test.js index 604ad14..b04b4c0 100644 --- a/tst/filters/ge.test.js +++ b/test/filters/ge.test.js @@ -15,7 +15,7 @@ var BerWriter = asn1.BerWriter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); GreaterThanEqualsFilter = filters.GreaterThanEqualsFilter; @@ -24,7 +24,7 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { var f = new GreaterThanEqualsFilter(); t.ok(f); t.ok(!f.attribute); @@ -33,7 +33,7 @@ test('Construct no args', function(t) { }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new GreaterThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -46,7 +46,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new GreaterThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -57,7 +57,7 @@ test('match true', function(t) { }); -test('match multiple', function(t) { +test('match multiple', function (t) { var f = new GreaterThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -67,7 +67,7 @@ test('match multiple', function(t) { t.end(); }); -test('match false', function(t) { +test('match false', function (t) { var f = new GreaterThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -78,7 +78,7 @@ test('match false', function(t) { }); -test('parse ok', function(t) { +test('parse ok', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeString('bar'); @@ -91,7 +91,7 @@ test('parse ok', function(t) { }); -test('parse bad', function(t) { +test('parse bad', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeInt(20); diff --git a/tst/filters/le.test.js b/test/filters/le.test.js similarity index 85% rename from tst/filters/le.test.js rename to test/filters/le.test.js index 545cdc3..f4a0f57 100644 --- a/tst/filters/le.test.js +++ b/test/filters/le.test.js @@ -15,7 +15,7 @@ var BerWriter = asn1.BerWriter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); LessThanEqualsFilter = filters.LessThanEqualsFilter; @@ -24,7 +24,7 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { var f = new LessThanEqualsFilter(); t.ok(f); t.ok(!f.attribute); @@ -33,7 +33,7 @@ test('Construct no args', function(t) { }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new LessThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -46,7 +46,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new LessThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -57,7 +57,7 @@ test('match true', function(t) { }); -test('match multiple', function(t) { +test('match multiple', function (t) { var f = new LessThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -68,7 +68,7 @@ test('match multiple', function(t) { }); -test('match false', function(t) { +test('match false', function (t) { var f = new LessThanEqualsFilter({ attribute: 'foo', value: 'bar' @@ -79,7 +79,7 @@ test('match false', function(t) { }); -test('parse ok', function(t) { +test('parse ok', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeString('bar'); @@ -92,7 +92,7 @@ test('parse ok', function(t) { }); -test('parse bad', function(t) { +test('parse bad', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeInt(20); diff --git a/tst/filters/not.test.js b/test/filters/not.test.js similarity index 84% rename from tst/filters/not.test.js rename to test/filters/not.test.js index 50b729d..5fc9566 100644 --- a/tst/filters/not.test.js +++ b/test/filters/not.test.js @@ -14,7 +14,7 @@ var NotFilter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); EqualityFilter = filters.EqualityFilter; @@ -25,13 +25,13 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { t.ok(new NotFilter()); t.end(); }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new NotFilter({ filter: new EqualityFilter({ attribute: 'foo', @@ -44,7 +44,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new NotFilter({ filter: new EqualityFilter({ attribute: 'foo', @@ -57,7 +57,7 @@ test('match true', function(t) { }); -test('match false', function(t) { +test('match false', function (t) { var f = new NotFilter({ filter: new EqualityFilter({ attribute: 'foo', @@ -68,5 +68,3 @@ test('match false', function(t) { t.ok(!f.matches({ foo: 'bar' })); t.end(); }); - - diff --git a/tst/filters/or.test.js b/test/filters/or.test.js similarity index 86% rename from tst/filters/or.test.js rename to test/filters/or.test.js index ee368b2..8622f78 100644 --- a/tst/filters/or.test.js +++ b/test/filters/or.test.js @@ -14,7 +14,7 @@ var OrFilter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); EqualityFilter = filters.EqualityFilter; @@ -25,13 +25,13 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { t.ok(new OrFilter()); t.end(); }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new OrFilter(); f.addFilter(new EqualityFilter({ attribute: 'foo', @@ -47,7 +47,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new OrFilter(); f.addFilter(new EqualityFilter({ attribute: 'foo', @@ -63,7 +63,7 @@ test('match true', function(t) { }); -test('match false', function(t) { +test('match false', function (t) { var f = new OrFilter(); f.addFilter(new EqualityFilter({ attribute: 'foo', @@ -77,5 +77,3 @@ test('match false', function(t) { t.ok(!f.matches({ foo: 'baz', zig: 'zonk' })); t.end(); }); - - diff --git a/tst/filters/parse.test.js b/test/filters/parse.test.js similarity index 82% rename from tst/filters/parse.test.js rename to test/filters/parse.test.js index 56c2fce..c4a4754 100644 --- a/tst/filters/parse.test.js +++ b/test/filters/parse.test.js @@ -6,20 +6,20 @@ var parse = require('../../lib/index').parseFilter; -test('GH-48 XML Strings in filter', function(t) { +test('GH-48 XML Strings in filter', function (t) { var str = '(&(CentralUIEnrollments=\\*)(objectClass=User))'; var f = parse(str); t.ok(f); t.ok(f.filters); t.equal(f.filters.length, 2); - f.filters.forEach(function(filter) { + f.filters.forEach(function (filter) { t.ok(filter.attribute); }); t.end(); }); -test('GH-50 = in filter', function(t) { +test('GH-50 = in filter', function (t) { var str = '(uniquemember=uuid=930896af-bf8c-48d4-885c-6573a94b1853, ' + 'ou=users, o=smartdc)'; var f = parse(str); @@ -31,7 +31,7 @@ test('GH-50 = in filter', function(t) { }); -test('( in filter', function(t) { +test('( in filter', function (t) { var str = '(foo=bar\\()'; var f = parse(str); t.ok(f); @@ -41,7 +41,7 @@ test('( in filter', function(t) { }); -test(') in filter', function(t) { +test(') in filter', function (t) { var str = '(foo=bar\\))'; var f = parse(str); t.ok(f); @@ -51,7 +51,7 @@ test(') in filter', function(t) { }); -test('\\ in filter', function(t) { +test('\\ in filter', function (t) { var str = '(foo=bar\\\\)'; var f = parse(str); t.ok(f); @@ -61,7 +61,7 @@ test('\\ in filter', function(t) { }); -test('* in equality filter', function(t) { +test('* in equality filter', function (t) { var str = '(foo=bar\\*)'; var f = parse(str); t.ok(f); @@ -71,7 +71,7 @@ test('* in equality filter', function(t) { }); -test('* substr filter (prefix)', function(t) { +test('* substr filter (prefix)', function (t) { var str = '(foo=bar*)'; var f = parse(str); t.ok(f); @@ -81,7 +81,7 @@ test('* substr filter (prefix)', function(t) { }); -test('GH-53 NotFilter', function(t) { +test('GH-53 NotFilter', function (t) { var str = '(&(objectClass=person)(!(objectClass=shadowAccount)))'; var f = parse(str); t.ok(f); diff --git a/tst/filters/presence.test.js b/test/filters/presence.test.js similarity index 83% rename from tst/filters/presence.test.js rename to test/filters/presence.test.js index ab10f0a..e97b28e 100644 --- a/tst/filters/presence.test.js +++ b/test/filters/presence.test.js @@ -15,7 +15,7 @@ var BerWriter = asn1.BerWriter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); PresenceFilter = filters.PresenceFilter; @@ -24,7 +24,7 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { var f = new PresenceFilter(); t.ok(f); t.ok(!f.attribute); @@ -32,7 +32,7 @@ test('Construct no args', function(t) { }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new PresenceFilter({ attribute: 'foo' }); @@ -43,7 +43,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new PresenceFilter({ attribute: 'foo' }); @@ -53,7 +53,7 @@ test('match true', function(t) { }); -test('match false', function(t) { +test('match false', function (t) { var f = new PresenceFilter({ attribute: 'foo' }); @@ -63,7 +63,7 @@ test('match false', function(t) { }); -test('parse ok', function(t) { +test('parse ok', function (t) { var writer = new BerWriter(); writer.writeString('foo', 0x87); diff --git a/tst/filters/substr.test.js b/test/filters/substr.test.js similarity index 88% rename from tst/filters/substr.test.js rename to test/filters/substr.test.js index a6201f8..df8af38 100644 --- a/tst/filters/substr.test.js +++ b/test/filters/substr.test.js @@ -15,7 +15,7 @@ var BerWriter = asn1.BerWriter; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { var filters = require('../../lib/index').filters; t.ok(filters); SubstringFilter = filters.SubstringFilter; @@ -24,7 +24,7 @@ test('load library', function(t) { }); -test('Construct no args', function(t) { +test('Construct no args', function (t) { var f = new SubstringFilter(); t.ok(f); t.ok(!f.attribute); @@ -33,7 +33,7 @@ test('Construct no args', function(t) { }); -test('Construct args', function(t) { +test('Construct args', function (t) { var f = new SubstringFilter({ attribute: 'foo', initial: 'bar', @@ -52,7 +52,7 @@ test('Construct args', function(t) { }); -test('match true', function(t) { +test('match true', function (t) { var f = new SubstringFilter({ attribute: 'foo', initial: 'bar', @@ -65,7 +65,7 @@ test('match true', function(t) { }); -test('match false', function(t) { +test('match false', function (t) { var f = new SubstringFilter({ attribute: 'foo', initial: 'bar', @@ -78,7 +78,7 @@ test('match false', function(t) { }); -test('match any', function(t) { +test('match any', function (t) { var f = new SubstringFilter({ attribute: 'foo', initial: 'bar' @@ -88,7 +88,7 @@ test('match any', function(t) { t.end(); }); -test('parse ok', function(t) { +test('parse ok', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.startSequence(); @@ -104,7 +104,7 @@ test('parse ok', function(t) { }); -test('parse bad', function(t) { +test('parse bad', function (t) { var writer = new BerWriter(); writer.writeString('foo'); writer.writeInt(20); diff --git a/tst/laundry.test.js b/test/laundry.test.js similarity index 78% rename from tst/laundry.test.js rename to test/laundry.test.js index 6843bcb..e44a394 100644 --- a/tst/laundry.test.js +++ b/test/laundry.test.js @@ -19,20 +19,20 @@ var server; ///--- Helper function search(t, options, callback) { - client.search(SUFFIX, options, function(err, res) { + client.search(SUFFIX, options, function (err, res) { t.ifError(err); t.ok(res); var found = false; - res.on('searchEntry', function(entry) { + res.on('searchEntry', function (entry) { t.ok(entry); found = true; }); - res.on('end', function() { + res.on('end', function () { t.ok(found); if (callback) return callback(); - t.end(); + return t.end(); }); }); } @@ -41,10 +41,10 @@ function search(t, options, callback) { ///--- Tests -test('setup', function(t) { +test('setup', function (t) { server = ldap.createServer(); t.ok(server); - server.listen(SOCKET, function() { + server.listen(SOCKET, function () { client = ldap.createClient({ socketPath: SOCKET }); @@ -52,11 +52,11 @@ test('setup', function(t) { t.end(); }); - server.bind('cn=root', function(req, res, next) { + server.bind('cn=root', function (req, res, next) { res.end(); return next(); }); - server.search(SUFFIX, function(req, res, next) { + server.search(SUFFIX, function (req, res, next) { var entry = { dn: 'cn=foo, ' + SUFFIX, attributes: { @@ -76,7 +76,7 @@ test('setup', function(t) { }); -test('Evolution search filter (GH-3)', function(t) { +test('Evolution search filter (GH-3)', function (t) { // This is what Evolution sends, when searching for a contact 'ogo'. Wow. var filter = '(|(cn=ogo*)(givenname=ogo*)(sn=ogo*)(mail=ogo*)(member=ogo*)' + @@ -100,7 +100,7 @@ test('Evolution search filter (GH-3)', function(t) { }); -test('GH-49 Client errors on bad attributes', function(t) { +test('GH-49 Client errors on bad attributes', function (t) { var searchOpts = { filter: 'cn=*ogo*', scope: 'one', @@ -110,19 +110,19 @@ test('GH-49 Client errors on bad attributes', function(t) { }); -test('GH-55 Client emits connect multiple times', function(t) { +test('GH-55 Client emits connect multiple times', function (t) { var c = ldap.createClient({ socketPath: SOCKET }); var count = 0; - c.on('connect', function(socket) { + c.on('connect', function (socket) { t.ok(socket); count++; }); - c.bind('cn=root', 'secret', function(err, res) { + c.bind('cn=root', 'secret', function (err, res) { t.ifError(err); - c.unbind(function() { + c.unbind(function () { t.equal(count, 1); t.end(); }); @@ -130,9 +130,9 @@ test('GH-55 Client emits connect multiple times', function(t) { }); -test('shutdown', function(t) { - client.unbind(function() { - server.on('close', function() { +test('shutdown', function (t) { + client.unbind(function () { + server.on('close', function () { t.end(); }); server.close(); diff --git a/tst/messages/add_request.test.js b/test/messages/add_request.test.js similarity index 94% rename from tst/messages/add_request.test.js rename to test/messages/add_request.test.js index 7bc6567..fe68e68 100644 --- a/tst/messages/add_request.test.js +++ b/test/messages/add_request.test.js @@ -15,7 +15,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { AddRequest = require('../../lib/index').AddRequest; Attribute = require('../../lib/index').Attribute; dn = require('../../lib/index').dn; @@ -26,13 +26,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new AddRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new AddRequest({ entry: dn.parse('cn=foo, o=test'), attributes: [new Attribute({type: 'cn', vals: ['foo']}), @@ -49,7 +49,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeString('cn=foo,o=test'); @@ -83,7 +83,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new AddRequest({ messageID: 123, entry: dn.parse('cn=foo, o=test'), @@ -115,7 +115,7 @@ test('toBer', function(t) { }); -test('toObject', function(t) { +test('toObject', function (t) { var req = new AddRequest({ entry: dn.parse('cn=foo, o=test'), attributes: [new Attribute({type: 'cn', vals: ['foo', 'bar']}), diff --git a/tst/messages/add_response.test.js b/test/messages/add_response.test.js similarity index 88% rename from tst/messages/add_response.test.js rename to test/messages/add_response.test.js index fb262e4..4b362e1 100644 --- a/tst/messages/add_response.test.js +++ b/test/messages/add_response.test.js @@ -14,20 +14,20 @@ var AddResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { AddResponse = require('../../lib/index').AddResponse; t.ok(AddResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new AddResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new AddResponse({ messageID: 123, status: 0 @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -54,7 +54,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new AddResponse({ messageID: 123, status: 3, diff --git a/tst/messages/bind_request.test.js b/test/messages/bind_request.test.js similarity index 90% rename from tst/messages/bind_request.test.js rename to test/messages/bind_request.test.js index 04b60a4..0acbb6e 100644 --- a/tst/messages/bind_request.test.js +++ b/test/messages/bind_request.test.js @@ -14,7 +14,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { BindRequest = require('../../lib/index').BindRequest; dn = require('../../lib/index').dn; t.ok(BindRequest); @@ -23,13 +23,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new BindRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new BindRequest({ version: 3, name: dn.parse('cn=root'), @@ -43,7 +43,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeInt(3); ber.writeString('cn=root'); @@ -60,7 +60,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new BindRequest({ messageID: 123, version: 3, diff --git a/tst/messages/bind_response.test.js b/test/messages/bind_response.test.js similarity index 88% rename from tst/messages/bind_response.test.js rename to test/messages/bind_response.test.js index 269270b..fd8caf7 100644 --- a/tst/messages/bind_response.test.js +++ b/test/messages/bind_response.test.js @@ -14,20 +14,20 @@ var BindResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { BindResponse = require('../../lib/index').BindResponse; t.ok(BindResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new BindResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new BindResponse({ messageID: 123, status: 0 @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -54,7 +54,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new BindResponse({ messageID: 123, status: 3, diff --git a/tst/messages/compare_request.test.js b/test/messages/compare_request.test.js similarity index 90% rename from tst/messages/compare_request.test.js rename to test/messages/compare_request.test.js index 68a1166..716d008 100644 --- a/tst/messages/compare_request.test.js +++ b/test/messages/compare_request.test.js @@ -14,7 +14,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { CompareRequest = require('../../lib/index').CompareRequest; dn = require('../../lib/index').dn; t.ok(CompareRequest); @@ -23,13 +23,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new CompareRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new CompareRequest({ entry: dn.parse('cn=foo, o=test'), attribute: 'sn', @@ -43,7 +43,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeString('cn=foo,o=test'); @@ -62,7 +62,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new CompareRequest({ messageID: 123, entry: dn.parse('cn=foo, o=test'), diff --git a/tst/messages/compare_response.test.js b/test/messages/compare_response.test.js similarity index 88% rename from tst/messages/compare_response.test.js rename to test/messages/compare_response.test.js index 837d1c9..fd4594c 100644 --- a/tst/messages/compare_response.test.js +++ b/test/messages/compare_response.test.js @@ -14,20 +14,20 @@ var CompareResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { CompareResponse = require('../../lib/index').CompareResponse; t.ok(CompareResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new CompareResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new CompareResponse({ messageID: 123, status: 0 @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -54,7 +54,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new CompareResponse({ messageID: 123, status: 3, diff --git a/tst/messages/del_request.test.js b/test/messages/del_request.test.js similarity index 87% rename from tst/messages/del_request.test.js rename to test/messages/del_request.test.js index 8e98f0f..ce55534 100644 --- a/tst/messages/del_request.test.js +++ b/test/messages/del_request.test.js @@ -15,7 +15,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { DeleteRequest = require('../../lib/index').DeleteRequest; dn = require('../../lib/index').dn; t.ok(DeleteRequest); @@ -23,13 +23,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new DeleteRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new DeleteRequest({ entry: dn.parse('cn=test') }); @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeString('cn=test', 0x4a); @@ -52,7 +52,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new DeleteRequest({ messageID: 123, entry: dn.parse('cn=test') diff --git a/tst/messages/del_response.test.js b/test/messages/del_response.test.js similarity index 88% rename from tst/messages/del_response.test.js rename to test/messages/del_response.test.js index 61b3916..ebecb5c 100644 --- a/tst/messages/del_response.test.js +++ b/test/messages/del_response.test.js @@ -14,20 +14,20 @@ var DeleteResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { DeleteResponse = require('../../lib/index').DeleteResponse; t.ok(DeleteResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new DeleteResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new DeleteResponse({ messageID: 123, status: 0 @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -54,7 +54,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new DeleteResponse({ messageID: 123, status: 3, diff --git a/tst/messages/ext_request.test.js b/test/messages/ext_request.test.js similarity index 88% rename from tst/messages/ext_request.test.js rename to test/messages/ext_request.test.js index e670269..656dbf3 100644 --- a/tst/messages/ext_request.test.js +++ b/test/messages/ext_request.test.js @@ -14,7 +14,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { ExtendedRequest = require('../../lib/index').ExtendedRequest; dn = require('../../lib/index').dn; t.ok(ExtendedRequest); @@ -23,13 +23,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new ExtendedRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new ExtendedRequest({ requestName: '1.2.3.4', requestValue: 'test' @@ -41,7 +41,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeString('1.2.3.4', 0x80); ber.writeString('test', 0x81); @@ -55,7 +55,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new ExtendedRequest({ messageID: 123, requestName: '1.2.3.4', diff --git a/tst/messages/ext_response.test.js b/test/messages/ext_response.test.js similarity index 91% rename from tst/messages/ext_response.test.js rename to test/messages/ext_response.test.js index e56ba01..b31559a 100644 --- a/tst/messages/ext_response.test.js +++ b/test/messages/ext_response.test.js @@ -14,20 +14,20 @@ var ExtendedResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { ExtendedResponse = require('../../lib/index').ExtendedResponse; t.ok(ExtendedResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new ExtendedResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new ExtendedResponse({ messageID: 123, status: 0, @@ -43,7 +43,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -62,7 +62,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new ExtendedResponse({ messageID: 123, status: 3, diff --git a/tst/messages/moddn_request.test.js b/test/messages/moddn_request.test.js similarity index 90% rename from tst/messages/moddn_request.test.js rename to test/messages/moddn_request.test.js index c73e7ac..375acff 100644 --- a/tst/messages/moddn_request.test.js +++ b/test/messages/moddn_request.test.js @@ -14,7 +14,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { ModifyDNRequest = require('../../lib/index').ModifyDNRequest; dn = require('../../lib/index').dn; t.ok(ModifyDNRequest); @@ -23,13 +23,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new ModifyDNRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new ModifyDNRequest({ entry: dn.parse('cn=foo, o=test'), newRdn: dn.parse('cn=foo2'), @@ -43,7 +43,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeString('cn=foo,o=test'); ber.writeString('cn=foo2'); @@ -59,7 +59,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new ModifyDNRequest({ messageID: 123, entry: dn.parse('cn=foo, o=test'), diff --git a/tst/messages/moddn_response.test.js b/test/messages/moddn_response.test.js similarity index 88% rename from tst/messages/moddn_response.test.js rename to test/messages/moddn_response.test.js index f5c3425..e257c8d 100644 --- a/tst/messages/moddn_response.test.js +++ b/test/messages/moddn_response.test.js @@ -14,20 +14,20 @@ var ModifyDNResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { ModifyDNResponse = require('../../lib/index').ModifyDNResponse; t.ok(ModifyDNResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new ModifyDNResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new ModifyDNResponse({ messageID: 123, status: 0 @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -54,7 +54,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new ModifyDNResponse({ messageID: 123, status: 3, diff --git a/tst/messages/modify_request.test.js b/test/messages/modify_request.test.js similarity index 93% rename from tst/messages/modify_request.test.js rename to test/messages/modify_request.test.js index 9e58e78..8b62727 100644 --- a/tst/messages/modify_request.test.js +++ b/test/messages/modify_request.test.js @@ -16,7 +16,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { ModifyRequest = require('../../lib/index').ModifyRequest; Attribute = require('../../lib/index').Attribute; Change = require('../../lib/index').Change; @@ -29,13 +29,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new ModifyRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new ModifyRequest({ object: dn.parse('cn=foo, o=test'), changes: [new Change({ @@ -53,7 +53,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeString('cn=foo,o=test'); ber.startSequence(); @@ -83,7 +83,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new ModifyRequest({ messageID: 123, object: dn.parse('cn=foo, o=test'), diff --git a/tst/messages/modify_response.test.js b/test/messages/modify_response.test.js similarity index 88% rename from tst/messages/modify_response.test.js rename to test/messages/modify_response.test.js index 1044303..f63993e 100644 --- a/tst/messages/modify_response.test.js +++ b/test/messages/modify_response.test.js @@ -14,20 +14,20 @@ var ModifyResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { ModifyResponse = require('../../lib/index').ModifyResponse; t.ok(ModifyResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new ModifyResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new ModifyResponse({ messageID: 123, status: 0 @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -54,7 +54,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new ModifyResponse({ messageID: 123, status: 3, diff --git a/tst/messages/search_entry.test.js b/test/messages/search_entry.test.js similarity index 94% rename from tst/messages/search_entry.test.js rename to test/messages/search_entry.test.js index 89b0157..7b41d53 100644 --- a/tst/messages/search_entry.test.js +++ b/test/messages/search_entry.test.js @@ -15,7 +15,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { SearchEntry = require('../../lib/index').SearchEntry; Attribute = require('../../lib/index').Attribute; dn = require('../../lib/index').dn; @@ -26,13 +26,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new SearchEntry()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new SearchEntry({ messageID: 123, objectName: dn.parse('cn=foo, o=test'), @@ -51,7 +51,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeString('cn=foo, o=test'); @@ -85,7 +85,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new SearchEntry({ messageID: 123, objectName: dn.parse('cn=foo, o=test'), diff --git a/tst/messages/search_request.test.js b/test/messages/search_request.test.js similarity index 94% rename from tst/messages/search_request.test.js rename to test/messages/search_request.test.js index d1fc8b5..6975731 100644 --- a/tst/messages/search_request.test.js +++ b/test/messages/search_request.test.js @@ -15,7 +15,7 @@ var dn; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { SearchRequest = require('../../lib/index').SearchRequest; EqualityFilter = require('../../lib/index').EqualityFilter; dn = require('../../lib/index').dn; @@ -26,13 +26,13 @@ test('load library', function(t) { }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new SearchRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new SearchRequest({ baseObject: dn.parse('cn=foo, o=test'), filter: new EqualityFilter({ @@ -51,7 +51,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var f = new EqualityFilter({ attribute: 'email', value: 'foo@bar.com' @@ -80,7 +80,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new SearchRequest({ messageID: 123, baseObject: dn.parse('cn=foo, o=test'), diff --git a/tst/messages/search_response.test.js b/test/messages/search_response.test.js similarity index 88% rename from tst/messages/search_response.test.js rename to test/messages/search_response.test.js index c6f17d0..83ffeb7 100644 --- a/tst/messages/search_response.test.js +++ b/test/messages/search_response.test.js @@ -14,20 +14,20 @@ var SearchResponse; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { SearchResponse = require('../../lib/index').SearchResponse; t.ok(SearchResponse); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new SearchResponse()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var res = new SearchResponse({ messageID: 123, status: 0 @@ -39,7 +39,7 @@ test('new with args', function(t) { }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); ber.writeEnumeration(0); ber.writeString('cn=root'); @@ -54,7 +54,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var res = new SearchResponse({ messageID: 123, status: 3, diff --git a/tst/messages/unbind_request.test.js b/test/messages/unbind_request.test.js similarity index 82% rename from tst/messages/unbind_request.test.js rename to test/messages/unbind_request.test.js index 759d0ab..058a124 100644 --- a/tst/messages/unbind_request.test.js +++ b/test/messages/unbind_request.test.js @@ -14,27 +14,27 @@ var UnbindRequest; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { UnbindRequest = require('../../lib/index').UnbindRequest; t.ok(UnbindRequest); t.end(); }); -test('new no args', function(t) { +test('new no args', function (t) { t.ok(new UnbindRequest()); t.end(); }); -test('new with args', function(t) { +test('new with args', function (t) { var req = new UnbindRequest({}); t.ok(req); t.end(); }); -test('parse', function(t) { +test('parse', function (t) { var ber = new BerWriter(); var req = new UnbindRequest(); @@ -43,7 +43,7 @@ test('parse', function(t) { }); -test('toBer', function(t) { +test('toBer', function (t) { var req = new UnbindRequest({ messageID: 123 }); diff --git a/tst/url.test.js b/test/url.test.js similarity index 86% rename from tst/url.test.js rename to test/url.test.js index 0a992b4..38a0ab1 100644 --- a/tst/url.test.js +++ b/test/url.test.js @@ -7,12 +7,13 @@ var test = require('tap').test; ///--- Globals var url; +var parseURL; ///--- Tests -test('load library', function(t) { +test('load library', function (t) { parseURL = require('../lib/index').parseURL; t.ok(parseURL); @@ -20,7 +21,7 @@ test('load library', function(t) { }); -test('parse empty', function(t) { +test('parse empty', function (t) { var u = parseURL('ldap:///'); t.equal(u.hostname, 'localhost'); t.equal(u.port, 389); @@ -31,7 +32,7 @@ test('parse empty', function(t) { }); -test('parse hostname', function(t) { +test('parse hostname', function (t) { var u = parseURL('ldap://example.com/'); t.equal(u.hostname, 'example.com'); t.equal(u.port, 389); @@ -42,7 +43,7 @@ test('parse hostname', function(t) { }); -test('parse host and port', function(t) { +test('parse host and port', function (t) { var u = parseURL('ldap://example.com:1389/'); t.equal(u.hostname, 'example.com'); t.equal(u.port, 1389); @@ -53,7 +54,7 @@ test('parse host and port', function(t) { }); -test('parse full', function(t) { +test('parse full', function (t) { var u = parseURL('ldaps://ldap.example.com:1389/dc=example%20,dc=com' + '?cn,sn?sub?(cn=Babs%20Jensen)'); diff --git a/tools/jsl.conf b/tools/jsl.node.conf old mode 100755 new mode 100644 similarity index 68% rename from tools/jsl.conf rename to tools/jsl.node.conf index 119319e..74b817d --- a/tools/jsl.conf +++ b/tools/jsl.node.conf @@ -1,6 +1,5 @@ # -# Configuration File for JavaScript Lint 0.3.0 -# Developed by Matthias Miller (http://www.JavaScriptLint.com) +# Configuration File for JavaScript Lint # # This configuration file can be used to lint a collection of scripts, or to enable # or disable warnings for scripts that are linted via the command line. @@ -10,59 +9,74 @@ # Enable or disable warnings based on requirements. # Use "+WarningName" to display or "-WarningName" to suppress. # -+no_return_value # function {0} does not always return a value -+duplicate_formal # duplicate formal argument {0} -+equal_as_assign # test for equality (==) mistyped as assignment (=)?{0} -+var_hides_arg # variable {0} hides argument -+redeclared_var # redeclaration of {0} {1} -+anon_no_return_value # anonymous function does not always return a value -+missing_semicolon # missing semicolon -+meaningless_block # meaningless block; curly braces have no impact ++ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent ++ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity ++ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement ++anon_no_return_value # anonymous function does not always return value ++assign_to_function_call # assignment to a function call +-block_without_braces # block statement without curly braces +comma_separated_stmts # multiple statements separated by commas (use semicolons?) --unreachable_code # unreachable code ++comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) ++default_not_at_end # the default case is not at the end of the switch statement ++dup_option_explicit # duplicate "option explicit" control comment ++duplicate_case_in_switch # duplicate case in switch statement ++duplicate_formal # duplicate formal argument {name} ++empty_statement # empty statement or extra semicolon ++identifier_hides_another # identifer {name} hides an identifier in a parent scope +-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement ++incorrect_version # Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version. ++invalid_fallthru # unexpected "fallthru" control comment ++invalid_pass # unexpected "pass" control comment ++jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax ++leading_decimal_point # leading decimal point may indicate a number or an object member ++legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax ++meaningless_block # meaningless block; curly braces have no impact ++mismatch_ctrl_comments # mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence ++misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma +missing_break # missing break statement +missing_break_for_last_case # missing break statement for last case in switch -+comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) --inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement -+useless_void # use of the void type may be unnecessary (void is always undefined) --useless_quotes # quotation marks are unnecessary ++missing_default_case # missing default case in switch statement ++missing_option_explicit # the "option explicit" control comment is missing ++missing_semicolon # missing semicolon ++missing_semicolon_for_lambda # missing semicolon for lambda assignment +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs -+use_of_label # use of label --block_without_braces # block statement without curly braces -+leading_decimal_point # leading decimal point may indicate a number or an object member -+trailing_decimal_point # trailing decimal point may indicate a number or an object member --octal_number # leading zeros make an octal number +nested_comment # nested comment -+misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma -+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement -+empty_statement # empty statement or extra semicolon --missing_option_explicit # the "option explicit" control comment is missing -+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag -+dup_option_explicit # duplicate "option explicit" control comment -+useless_assign # useless assignment -+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity -+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent) --missing_default_case # missing default case in switch statement -+duplicate_case_in_switch # duplicate case in switch statements -+default_not_at_end # the default case is not at the end of the switch statement -+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax -+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax -+useless_comparison # useless comparison; comparing identical expressions -+with_statement # with statement hides undeclared variables; use temporary variable instead -+trailing_comma_in_array # extra comma is not recommended in array initializers -+assign_to_function_call # assignment to a function call ++no_return_value # function {name} does not always return a value ++octal_number # leading zeros make an octal number +parseint_missing_radix # parseInt missing radix parameter -+unreferenced_argument # argument declared but never referenced: {name} -+unreferenced_function # function declared but not referenced ++partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag ++redeclared_var # redeclaration of {name} ++trailing_comma_in_array # extra comma is not recommended in array initializers ++trailing_decimal_point # trailing decimal point may indicate a number or an object member ++undeclared_identifier # undeclared identifier: {name} ++unreachable_code # unreachable code +-unreferenced_argument # argument declared but never referenced: {name} +-unreferenced_function # function is declared but never referenced: {name} ++unreferenced_variable # variable is declared but never referenced: {name} ++unsupported_version # JavaScript {version} is not supported ++use_of_label # use of label ++useless_assign # useless assignment ++useless_comparison # useless comparison; comparing identical expressions +-useless_quotes # the quotation marks are unnecessary ++useless_void # use of the void type may be unnecessary (void is always undefined) ++var_hides_arg # variable {name} hides argument ++want_assign_or_call # expected an assignment or function call ++with_statement # with statement hides undeclared variables; use temporary variable instead -identifier_hides_another --empty_statement ### Output format # Customize the format of the error message. # __FILE__ indicates current file path # __FILENAME__ indicates current file name # __LINE__ indicates current line -# __ERROR__ indicates error message +# __COL__ indicates current column +# __ERROR__ indicates error message (__ERROR_PREFIX__: __ERROR_MSG__) +# __ERROR_NAME__ indicates error name (used in configuration file) +# __ERROR_PREFIX__ indicates error prefix +# __ERROR_MSG__ indicates error message +# +# For machine-friendly output, the output format can be prefixed with +# "encode:". If specified, all items will be encoded with C-slashes. # # Visual Studio syntax (default): +output-format __FILE__(__LINE__): __ERROR__ @@ -77,33 +91,13 @@ +context -### Semicolons -# By default, assignments of an anonymous function to a variable or -# property (such as a function prototype) must be followed by a semicolon. -# -#+lambda_assign_requires_semicolon # deprecated setting - - ### Control Comments # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason, # although legacy control comments are enabled by default for backward compatibility. # -+legacy_control_comments - - -### JScript Function Extensions -# JScript allows member functions to be defined like this: -# function MyObj() { /*constructor*/ } -# function MyObj.prototype.go() { /*member function*/ } -# -# It also allows events to be attached like this: -# function window::onload() { /*init page*/ } -# -# This is a Microsoft-only JavaScript extension. Enable this setting to allow them. -# -#-jscript_function_extensions # deprecated setting +-legacy_control_comments ### Defining identifiers @@ -115,21 +109,25 @@ # (Use this in conjunction with the "undeclared identifier" warning.) # # Common uses for webpages might be: ++define __dirname ++define clearInterval ++define clearTimeout ++define console ++define exports +define global ++define module +define process +define require -+define exports -+define setTimeout -+define clearTimeout +define setInterval -+define clearInterval -+define JSON -+define console -+define __dirname -+define __filename ++define setTimeout +define Buffer -+define module ++define JSON ++define Math +### JavaScript Version +# To change the default JavaScript version: +#+default-type text/javascript;version=1.5 +#+default-type text/javascript;e4x=1 ### Files # Specify which files to lint @@ -137,4 +135,4 @@ # To add a set of files, use "+process FileName", "+process Folder\Path\*.js", # or "+process Folder\Path\*.htm". # -#+process jsl-test.js + diff --git a/tools/jsstyle.conf b/tools/jsstyle.conf new file mode 100644 index 0000000..2f11f48 --- /dev/null +++ b/tools/jsstyle.conf @@ -0,0 +1,4 @@ +indent=2 +doxygen +unparenthesized-return=0 +blank-after-start-comment=0 \ No newline at end of file From 4683b1e7674d3aa7e190fd92001a3121ef5f9d8d Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 18 Feb 2012 08:18:42 +0000 Subject: [PATCH 20/24] missing Makefile.targ due to gitignore --- .gitignore | 2 +- Makefile.targ | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 Makefile.targ diff --git a/.gitignore b/.gitignore index 085ef65..c71239f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ build node_modules *.log *.ldif -*.tar* +*.tar.* diff --git a/Makefile.targ b/Makefile.targ new file mode 100644 index 0000000..453760a --- /dev/null +++ b/Makefile.targ @@ -0,0 +1,220 @@ +# +# Copyright (c) 2012, Joyent, Inc. All rights reserved. +# +# Makefile.targ: common targets. +# +# NOTE: This makefile comes from the "eng" repo. It's designed to be dropped +# into other repos as-is without requiring any modifications. If you find +# yourself changing this file, you should instead update the original copy in +# eng.git and then update your repo to use the new version. +# +# This Makefile defines several useful targets and rules. You can use it by +# including it from a Makefile that specifies some of the variables below. +# +# Targets defined in this Makefile: +# +# check Checks JavaScript files for lint and style +# Checks bash scripts for syntax +# Checks SMF manifests for validity against the SMF DTD +# +# clean Removes built files +# +# docs Builds restdown documentation in docs/ +# +# prepush Depends on "check" and "test" +# +# test Does nothing (you should override this) +# +# xref Generates cscope (source cross-reference index) +# +# For details on what these targets are supposed to do, see the Joyent +# Engineering Guide. +# +# To make use of these targets, you'll need to set some of these variables. Any +# variables left unset will simply not be used. +# +# BASH_FILES Bash scripts to check for syntax +# (paths relative to top-level Makefile) +# +# CLEAN_FILES Files to remove as part of the "clean" target. Note +# that files generated by targets in this Makefile are +# automatically included in CLEAN_FILES. These include +# restdown-generated HTML and JSON files. +# +# DOC_FILES Restdown (documentation source) files. These are +# assumed to be contained in "docs/", and must NOT +# contain the "docs/" prefix. +# +# JSL_CONF_NODE Specify JavaScriptLint configuration files +# JSL_CONF_WEB (paths relative to top-level Makefile) +# +# Node.js and Web configuration files are separate +# because you'll usually want different global variable +# configurations. If no file is specified, none is given +# to jsl, which causes it to use a default configuration, +# which probably isn't what you want. +# +# JSL_FILES_NODE JavaScript files to check with Node config file. +# JSL_FILES_WEB JavaScript files to check with Web config file. +# +# SMF_MANIFESTS XML files to check for validity using the SMF DTD. +# +# You can also override these variables: +# +# BASH Path to bash (default: bash) +# +# JSL Path to JavaScriptLint (default: "jsl") +# +# JSL_FLAGS_NODE Additional flags to pass through to JSL +# JSL_FLAGS_WEB +# JSL_FLAGS +# +# JSSTYLE Path to jsstyle (default: jsstyle) +# +# JSSTYLE_FLAGS Additional flags to pass through to jsstyle +# + +# +# Defaults for the various tools we use. +# +BASH ?= bash +CP ?= cp +JSL ?= jsl +JSSTYLE ?= jsstyle +MKDIR ?= mkdir -p +MV ?= mv +RESTDOWN ?= restdown +RMTREE ?= rm -rf +JSL_FLAGS ?= --nologo --nosummary + +# +# Defaults for other fixed values. +# +DOC_BUILD = build/docs/public + +# +# Configure JSL_FLAGS_{NODE,WEB} based on JSL_CONF_{NODE,WEB}. +# +ifneq ($(origin JSL_CONF_NODE), undefined) + JSL_FLAGS_NODE += --conf=$(JSL_CONF_NODE) +endif + +ifneq ($(origin JSL_CONF_WEB), undefined) + JSL_FLAGS_WEB += --conf=$(JSL_CONF_WEB) +endif + +.PHONY: check-jsl check-jsl-node check-jsl-web +check-jsl: check-jsl-node check-jsl-web + +check-jsl-node: $(JSL_FILES_NODE:%=%.jslnodechk) + +check-jsl-web: $(JSL_FILES_WEB:%=%.jslwebchk) + +%.jslnodechk: % $(JSL_SCRIPT) + $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_NODE) $< + +%.jslwebchk: % $(JSL_SCRIPT) + $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_WEB) $< + +.PHONY: check-jsstyle +check-jsstyle: $(JSSTYLE_FILES:%=%.jsstylechk) + +%.jsstylechk: % $(JSSTYLE_SCRIPT) + $(JSSTYLE) $(JSSTYLE_FLAGS) $< + +.PHONY: check +check: check-jsl check-jsstyle + @echo check ok + +.PHONY: clean +clean: + -$(RMTREE) $(CLEAN_FILES) + +# +# The "docs" target is complicated because we do several things here: +# +# (1) Use restdown to build HTML and JSON files from each of DOC_FILES. +# +# (2) Copy these files into $(DOC_BUILD) (build/docs/public), which +# functions as a complete copy of the documentation that could be +# mirrored or served over HTTP. +# +# (3) Then copy any directories and media from docs/media into +# $(DOC_BUILD)/media. This allows projects to include their own media, +# including files that will override same-named files provided by +# restdown. +# +# Step (3) is the surprisingly complex part: in order to do this, we need to +# identify the subdirectories in docs/media, recreate them in +# $(DOC_BUILD)/media, then do the same with the files. +# +DOC_MEDIA_DIRS := $(shell find docs/branding/media -type d | grep -v "^docs/branding/media$$") +DOC_MEDIA_DIRS := $(DOC_MEDIA_DIRS:docs/branding/media/%=%) +DOC_MEDIA_DIRS_BUILD := $(DOC_MEDIA_DIRS:%=$(DOC_BUILD)/media/%) + +DOC_MEDIA_FILES := $(shell find docs/branding/media -type f) +DOC_MEDIA_FILES := $(DOC_MEDIA_FILES:docs/media/%=%) +DOC_MEDIA_FILES_BUILD := $(DOC_MEDIA_FILES:%=$(DOC_BUILD)/media/%) + +# +# Like the other targets, "docs" just depends on the final files we want to +# create in $(DOC_BUILD), leveraging other targets and recipes to define how +# to get there. +# +.PHONY: docs +docs: \ + $(DOC_FILES:%.md=$(DOC_BUILD)/%.html) \ + $(DOC_FILES:%.md=$(DOC_BUILD)/%.json) \ + $(DOC_MEDIA_FILES_BUILD) + +# +# We keep the intermediate files so that the next build can see whether the +# files in DOC_BUILD are up to date. +# +.PRECIOUS: \ + $(DOC_FILES:%.md=docs/%.html) \ + $(DOC_FILES:%.md=docs/%json) + +# +# We do clean those intermediate files, as well as all of DOC_BUILD. +# +CLEAN_FILES += \ + $(DOC_BUILD) \ + $(DOC_FILES:%.md=docs/%.html) \ + $(DOC_FILES:%.md=docs/%.json) + +# +# Before installing the files, we must make sure the directories exist. The | +# syntax tells make that the dependency need only exist, not be up to date. +# Otherwise, it might try to rebuild spuriously because the directory itself +# appears out of date. +# +$(DOC_MEDIA_FILES_BUILD): | $(DOC_MEDIA_DIRS_BUILD) + +$(DOC_BUILD)/%: docs/% | $(DOC_BUILD) + $(CP) $< $@ + $(RM) $< + +docs/%.json docs/%.html: docs/%.md | $(DOC_BUILD) + $(RESTDOWN) -b ./docs/branding -m $(DOC_BUILD) $< + +$(DOC_BUILD): + $(MKDIR) $@ + +info: + echo "DOC_MEDIA_FILES is '$(DOC_MEDIA_FILES)'" + echo "DOC_MEDIA_FILES_BUILD is '$(DOC_MEDIA_FILES_BUILD)'" + +$(DOC_MEDIA_DIRS_BUILD): + $(MKDIR) $@ + +# +# The default "test" target does nothing. This should usually be overridden by +# the parent Makefile. It's included here so we can define "prepush" without +# requiring the repo to define "test". +# +.PHONY: test +test: + +.PHONY: prepush +prepush: check test From 4f68abb36499e22440575e6e30c9b17954ebb2b8 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 18 Feb 2012 08:26:50 +0000 Subject: [PATCH 21/24] travis broken --- .travis.yml | 1 - package.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f1d0f13..2d26206 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ language: node_js node_js: - - 0.4 - 0.6 diff --git a/package.json b/package.json index 632c244..10dd2d7 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,6 @@ "node-uuid": "1.3.3" }, "scripts": { - "test": "./node_modules/.bin/tap ./tst" + "test": "./node_modules/.bin/tap ./test" } } From 7ff50f43f4a21121a5bb059ac468f4b55cef3e84 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 18 Feb 2012 08:54:22 +0000 Subject: [PATCH 22/24] Initial switch to bunyan --- lib/client.js | 48 +++++----- lib/index.js | 25 +++++- lib/log_stub.js | 155 -------------------------------- lib/messages/message.js | 13 +-- lib/messages/parser.js | 9 +- lib/messages/result.js | 2 +- lib/messages/search_response.js | 8 +- lib/messages/unbind_request.js | 3 +- lib/messages/unbind_response.js | 3 +- lib/server.js | 25 +++--- test/client.test.js | 2 - 11 files changed, 67 insertions(+), 226 deletions(-) delete mode 100644 lib/log_stub.js diff --git a/lib/client.js b/lib/client.js index 173c4d6..faddcd9 100644 --- a/lib/client.js +++ b/lib/client.js @@ -13,7 +13,6 @@ var Protocol = require('./protocol'); var dn = require('./dn'); var errors = require('./errors'); var filters = require('./filters'); -var logStub = require('./log_stub'); var messages = require('./messages'); var url = require('./url'); @@ -98,8 +97,8 @@ util.inherits(ConnectionError, errors.LDAPError); * * The options object is required, and must contain either a URL (string) or * a socketPath (string); the socketPath is only if you want to talk to an LDAP - * server over a Unix Domain Socket. Additionally, you can pass in a log4js - * option that is the result of `require('log4js')`, presumably after you've + * server over a Unix Domain Socket. Additionally, you can pass in a bunyan + * option that is the result of `new Logger()`, presumably after you've * configured it. * * @param {Object} options must have either url or socketPath. @@ -112,8 +111,8 @@ function Client(options) { throw new TypeError('options.url (string) required'); if (options.socketPath && typeof (options.socketPath) !== 'string') throw new TypeError('options.socketPath must be a string'); - if (options.log4js && typeof (options.log4js) !== 'object') - throw new TypeError('options.log4s must be an object'); + if (typeof (options.log) !== 'object') + throw new TypeError('options.log must be an object'); if (!xor(options.url, options.socketPath)) throw new TypeError('options.url ^ options.socketPath required'); @@ -134,19 +133,12 @@ function Client(options) { host: self.url ? self.url.hostname : undefined, socketPath: options.socketPath || undefined }; - this.log4js = options.log4js || logStub; + this.log = options.log; this.reconnect = (typeof (options.reconnect) === 'number' ? options.reconnect : 1000); this.shutdown = false; this.timeout = options.timeout || false; - this.__defineGetter__('log', function () { - if (!self._log) - self._log = self.log4js.getLogger('Client'); - - return self._log; - }); - return this.connect(function () {}); } util.inherits(Client, EventEmitter); @@ -760,8 +752,8 @@ Client.prototype._send = function (message, expect, callback, connection) { if (timer) clearTimeout(timer); - if (self.log.isDebugEnabled()) - self.log.debug('%s: response received: %j', conn.ldap.id, res.json); + if (self.log.debug()) + self.log.debug({res: res.json}, '%s: response received', conn.ldap.id); var err = null; @@ -836,8 +828,8 @@ Client.prototype._send = function (message, expect, callback, connection) { } // Finally send some data - if (this.log.isDebugEnabled()) - this.log.debug('%s: sending request: %j', conn.ldap.id, message.json); + if (this.log.debug()) + this.log.debug({msg: message.json}, '%s: sending request', conn.ldap.id); return conn.write(message.toBer(), _writeCb); } catch (e) { return closeConn(e); @@ -853,7 +845,7 @@ Client.prototype._newConnection = function () { if (this.secure) { c = tls.connect(connectOpts.port, connectOpts.host, function () { - if (log.isTraceEnabled()) + if (log.trace()) log.trace('%s connect event', c.ldap.id); c.ldap.connected = true; @@ -869,7 +861,7 @@ Client.prototype._newConnection = function () { assert.ok(c); c.parser = new Parser({ - log4js: self.log4js + log: self.log }); // Wrap the events @@ -886,7 +878,7 @@ Client.prototype._newConnection = function () { }); c.on('connect', function () { - if (log.isTraceEnabled()) + if (log.trace()) log.trace('%s connect event', c.ldap.id); c.ldap.connected = true; @@ -895,14 +887,14 @@ Client.prototype._newConnection = function () { }); c.on('end', function () { - if (log.isTraceEnabled()) + if (log.trace()) log.trace('%s end event', c.ldap.id); c.end(); }); c.on('close', function (had_err) { - if (log.isTraceEnabled()) + if (log.trace()) log.trace('%s close event had_err=%s', c.ldap.id, had_err ? 'yes' : 'no'); Object.keys(c.ldap.messages).forEach(function (msgid) { @@ -933,8 +925,8 @@ Client.prototype._newConnection = function () { }); c.on('error', function (err) { - if (log.isTraceEnabled()) - log.trace('%s error event=%s', c.ldap.id, err ? err.stack : '?'); + if (log.trace()) + log.trace({err: err}, '%s error event', c.ldap.id); if (self.listeners('error').length) self.emit('error', err); @@ -943,7 +935,7 @@ Client.prototype._newConnection = function () { }); c.on('timeout', function () { - if (log.isTraceEnabled()) + if (log.trace()) log.trace('%s timeout event=%s', c.ldap.id); self.emit('timeout'); @@ -951,7 +943,7 @@ Client.prototype._newConnection = function () { }); c.on('data', function (data) { - if (log.isTraceEnabled()) + if (log.trace()) log.trace('%s data event: %s', c.ldap.id, util.inspect(data)); c.parser.write(data); @@ -971,8 +963,8 @@ Client.prototype._newConnection = function () { }); c.parser.on('error', function (err) { - if (log.isTraceEnabled()) - log.trace('%s error event=%s', c.ldap.id, err ? err.stack : '?'); + if (log.trace()) + log.trace({err: err}, '%s error event', c.ldap.id); if (self.listeners('error').length) self.emit('error', err); diff --git a/lib/index.js b/lib/index.js index d460259..fd5f597 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,7 @@ // Copyright 2011 Mark Cavage, Inc. All rights reserved. +var Logger = require('bunyan'); + var Client = require('./client'); var Attribute = require('./attribute'); var Change = require('./change'); @@ -11,7 +13,6 @@ var controls = require('./controls'); var dn = require('./dn'); var errors = require('./errors'); var filters = require('./filters'); -var logStub = require('./log_stub'); var messages = require('./messages'); var url = require('./url'); @@ -45,11 +46,32 @@ module.exports = { if (typeof (options) !== 'object') throw new TypeError('options (object) required'); + if (!options.log) { + options.log = new Logger({ + name: 'ldapjs', + component: 'client', + stream: process.stderr + }); + } return new Client(options); }, Server: Server, createServer: function (options) { + if (options === undefined) + options = {}; + + if (typeof (options) !== 'object') + throw new TypeError('options (object) required'); + + if (!options.log) { + options.log = new Logger({ + name: 'ldapjs', + component: 'client', + stream: process.stderr + }); + } + return new Server(options); }, @@ -64,7 +86,6 @@ module.exports = { filters: filters, parseFilter: filters.parseString, - log4js: logStub, parseURL: url.parse, url: url }; diff --git a/lib/log_stub.js b/lib/log_stub.js deleted file mode 100644 index 43d5d22..0000000 --- a/lib/log_stub.js +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2011 Mark Cavage, Inc. All rights reserved. - - - -///--- Globals - -var FMT_STR = '%d-%s-%s %s:%s:%sZ %s - %s: '; - -var _i = 0; -var LEVELS = { - Trace: _i++, - Debug: _i++, - Info: _i++, - Warn: _i++, - Error: _i++, - Fatal: _i++ -}; - -var level = 'Info'; - - - -// --- Helpers - -function pad(val) { - if (parseInt(val, 10) < 10) { - val = '0' + val; - } - return val; -} - - -function format(level, name, args) { - var d = new Date(); - var fmtStr = args.shift(); - var fmtArgs = [ - d.getUTCFullYear(), - pad(d.getUTCMonth() + 1), - pad(d.getUTCDate()), - pad(d.getUTCHours()), - pad(d.getUTCMinutes()), - pad(d.getUTCSeconds()), - level, - name - ]; - - args = fmtArgs.concat(args); - - var output = (FMT_STR + fmtStr).replace(/%[sdj]/g, function (match) { - switch (match) { - case '%s': return new String(args.shift()); - case '%d': return new Number(args.shift()); - case '%j': return JSON.stringify(args.shift()); - default: - return match; - } - }); - - return output; -} - - - -///--- API - -function Log(name) { - this.name = name; -} - -Log.prototype._write = function (level, args) { - var data = format(level, this.name, args); - console.error(data); -}; - -Log.prototype.isTraceEnabled = function () { - return (LEVELS.Trace >= LEVELS[level]); -}; - -Log.prototype.trace = function () { - if (this.isTraceEnabled()) - this._write('TRACE', Array.prototype.slice.call(arguments)); -}; - -Log.prototype.isDebugEnabled = function () { - return (LEVELS.Debug >= LEVELS[level]); -}; - -Log.prototype.debug = function () { - if (this.isDebugEnabled()) - this._write('DEBUG', Array.prototype.slice.call(arguments)); -}; - -Log.prototype.isInfoEnabled = function () { - return (LEVELS.Info >= LEVELS[level]); -}; - -Log.prototype.info = function () { - if (this.isInfoEnabled()) - this._write('INFO', Array.prototype.slice.call(arguments)); -}; - -Log.prototype.isWarnEnabled = function () { - return (LEVELS.Warn >= LEVELS[level]); -}; - -Log.prototype.warn = function () { - if (this.isWarnEnabled()) - this._write('WARN', Array.prototype.slice.call(arguments)); -}; - -Log.prototype.isErrorEnabled = function () { - return (LEVELS.Error >= LEVELS[level]); -}; - -Log.prototype.error = function () { - if (this.isErrorEnabled()) - this._write('ERROR', Array.prototype.slice.call(arguments)); -}; - -Log.prototype.isFatalEnabled = function () { - return (LEVELS.Fatal >= LEVELS[level]); -}; - -Log.prototype.fatal = function () { - if (this.isFatalEnabled()) - this._write('FATAL', Array.prototype.slice.call(arguments)); -}; - - -module.exports = { - - setLevel: function (l) { - l = l.charAt(0).toUpperCase() + l.slice(1).toLowerCase(); - if (LEVELS[l] !== undefined) - level = l; - - return level; - }, - - getLogger: function (name) { - if (!name || typeof (name) !== 'string') - throw new TypeError('name (string) required'); - - return new Log(name); - }, - - setGlobalLogLevel: function (l) { - l = l.charAt(0).toUpperCase() + l.slice(1).toLowerCase(); - if (LEVELS[l] !== undefined) - level = l; - - return level; - } - -}; diff --git a/lib/messages/message.js b/lib/messages/message.js index 2f2dda4..516f650 100644 --- a/lib/messages/message.js +++ b/lib/messages/message.js @@ -8,8 +8,6 @@ var asn1 = require('asn1'); var Control = require('../controls').Control; var Protocol = require('../protocol'); -var logStub = require('../log_stub'); - ///--- Globals @@ -37,7 +35,7 @@ function LDAPMessage(options) { this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; - this.log4js = options.log4js || logStub; + this.log = options.log; var self = this; this.__defineGetter__('id', function () { return self.messageID; }); @@ -52,11 +50,6 @@ function LDAPMessage(options) { j.controls = self.controls; return j; }); - this.__defineGetter__('log', function () { - if (!self._log) - self._log = self.log4js.getLogger(self.type); - return self._log; - }); } module.exports = LDAPMessage; @@ -69,7 +62,7 @@ LDAPMessage.prototype.toString = function () { LDAPMessage.prototype.parse = function (ber) { assert.ok(ber); - if (this.log.isTraceEnabled()) + if (this.log.trace()) this.log.trace('parse: data=%s', util.inspect(ber.buffer)); // Delegate off to the specific type to parse @@ -86,7 +79,7 @@ LDAPMessage.prototype.parse = function (ber) { } } - if (this.log.isTraceEnabled()) + if (this.log.trace()) this.log.trace('Parsing done: %j', this.json); return true; }; diff --git a/lib/messages/parser.js b/lib/messages/parser.js index b2e5f7a..ee26168 100644 --- a/lib/messages/parser.js +++ b/lib/messages/parser.js @@ -50,14 +50,13 @@ var BerReader = asn1.BerReader; function Parser(options) { if (!options || typeof (options) !== 'object') throw new TypeError('options (object) required'); - if (!options.log4js || typeof (options.log4js) !== 'object') - throw new TypeError('options.log4js (object) required'); + if (typeof (options.log) !== 'object') + throw new TypeError('options.log (object) required'); EventEmitter.call(this); this.buffer = null; - this.log4js = options.log4js; - this.log = this.log4js.getLogger('Parser'); + this.log = options.log; } util.inherits(Parser, EventEmitter); module.exports = Parser; @@ -219,6 +218,6 @@ Parser.prototype.getMessage = function (ber) { return new Message({ messageID: messageID, - log4js: self.log4js + log: self.log }); }; diff --git a/lib/messages/result.js b/lib/messages/result.js index 3c437bf..0285cf9 100644 --- a/lib/messages/result.js +++ b/lib/messages/result.js @@ -65,7 +65,7 @@ LDAPResult.prototype.end = function (status) { this.status = status; var ber = this.toBer(); - if (this.log.isDebugEnabled()) + if (this.log.debug()) this.log.debug('%s: sending: %j', this.connection.ldap.id, this.json); try { diff --git a/lib/messages/search_response.js b/lib/messages/search_response.js index e0f3c00..4e8c276 100644 --- a/lib/messages/search_response.js +++ b/lib/messages/search_response.js @@ -81,13 +81,13 @@ SearchResponse.prototype.send = function (entry, nofiltering) { entry = new SearchEntry({ objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn, messageID: self.messageID, - log4js: self.log4js + log: self.log }); entry.fromObject(save); } try { - if (this.log.isDebugEnabled()) + if (this.log.debug()) this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.json); this.connection.write(entry.toBer()); @@ -128,7 +128,7 @@ SearchResponse.prototype.createSearchEntry = function (object) { var entry = new SearchEntry({ messageID: self.messageID, - log4js: self.log4js, + log: self.log, objectName: object.objectName || object.dn }); entry.fromObject((object.attributes || object)); @@ -152,7 +152,7 @@ SearchResponse.prototype.createSearchReference = function (uris) { var self = this; return new SearchReference({ messageID: self.messageID, - log4js: self.log4js, + log: self.log, uris: uris }); }; diff --git a/lib/messages/unbind_request.js b/lib/messages/unbind_request.js index 224fad1..bafa060 100644 --- a/lib/messages/unbind_request.js +++ b/lib/messages/unbind_request.js @@ -55,8 +55,7 @@ UnbindRequest.prototype.newResult = function () { } util.inherits(UnbindResponse, LDAPMessage); UnbindResponse.prototype.end = function (status) { - if (this.log.isTraceEnabled()) - this.log.trace('%s: unbinding!', this.connection.ldap.id); + this.log.trace('%s: unbinding!', this.connection.ldap.id); this.connection.end(); }; UnbindResponse.prototype._json = function (j) { return j; }; diff --git a/lib/messages/unbind_response.js b/lib/messages/unbind_response.js index 1fb209e..c1d8d87 100644 --- a/lib/messages/unbind_response.js +++ b/lib/messages/unbind_response.js @@ -36,8 +36,7 @@ module.exports = UnbindResponse; UnbindResponse.prototype.end = function (status) { assert.ok(this.connection); - if (this.log.isTraceEnabled()) - this.log.trace('%s: unbinding!', this.connection.ldap.id); + this.log.trace('%s: unbinding!', this.connection.ldap.id); this.connection.end(); diff --git a/lib/server.js b/lib/server.js index a6f5312..8b6f4cb 100644 --- a/lib/server.js +++ b/lib/server.js @@ -12,7 +12,6 @@ var dn = require('./dn'); var dtrace = require('./dtrace'); var errors = require('./errors'); var Protocol = require('./protocol'); -var logStub = require('./log_stub'); var Parser = require('./messages').Parser; var AbandonResponse = require('./messages/abandon_response'); @@ -114,7 +113,7 @@ function getResponse(req) { var res = new Response({ messageID: req.messageID, - log4js: req.log4js, + log: req.log, attributes: ((req instanceof SearchRequest) ? req.attributes : undefined) }); res.connection = req.connection; @@ -241,7 +240,7 @@ function fireDTraceProbe(req, res) { * LDAP operations however. * * The options object currently only takes a certificate/private key, and a - * log4js handle. + * bunyan logger handle. * * This object exposes the following events: * - 'error' @@ -254,8 +253,8 @@ function Server(options) { if (options) { if (typeof (options) !== 'object') throw new TypeError('options (object) required'); - if (options.log4js && typeof (options.log4js) !== 'object') - throw new TypeError('options.log4s must be an object'); + if (typeof (options.log) !== 'object') + throw new TypeError('options.log must be an object'); if (options.certificate || options.key) { if (!(options.certificate && options.key) || @@ -269,14 +268,11 @@ function Server(options) { options = {}; } var self = this; - if (!options.log4js) - options.log4js = logStub; EventEmitter.call(this, options); this._chain = []; - this.log4js = options.log4js; - this.log = this.log4js.getLogger('Server'); + this.log = options.log; var log = this.log; @@ -330,22 +326,21 @@ function Server(options) { function newConnection(c) { setupConnection(c); - if (log.isTraceEnabled()) - log.trace('new connection from %s', c.ldap.id); + log.trace('new connection from %s', c.ldap.id); dtrace.fire('server-connection', function () { return [c.remoteAddress]; }); c.parser = new Parser({ - log4js: options.log4js + log: options.log }); c.parser.on('message', function (req) { req.connection = c; req.logId = c.ldap.id + '::' + req.messageID; req.startTime = new Date().getTime(); - if (log.isDebugEnabled()) + if (log.debug()) log.debug('%s: message received: req=%j', c.ldap.id, req.json); var res = getResponse(req); @@ -424,7 +419,7 @@ function Server(options) { }); c.on('data', function (data) { - if (log.isTraceEnabled()) + if (log.trace()) log.trace('data on %s: %s', c.ldap.id, util.inspect(data)); try { @@ -448,7 +443,7 @@ function Server(options) { } else { this.server = net.createServer(newConnection); } - this.server.log4js = options.log4js; + this.server.log = options.log; this.server.ldap = { config: options }; diff --git a/test/client.test.js b/test/client.test.js index 3f7e622..95b9501 100644 --- a/test/client.test.js +++ b/test/client.test.js @@ -132,8 +132,6 @@ test('setup', function (t) { reconnect: false // turn this off for unit testing }); t.ok(client); - // client.log4js.setLevel('Trace'); - // server.log4js.setLevel('Trace'); t.end(); }); From 15c6e328015ba602db4ad3454b7e9485af7c4e26 Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 18 Feb 2012 11:47:58 -0800 Subject: [PATCH 23/24] add logger to del_request test --- Makefile | 4 ++-- test/messages/del_request.test.js | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f9f3ee4..cf675ca 100644 --- a/Makefile +++ b/Makefile @@ -42,8 +42,8 @@ all: $(NPM) install .PHONY: test -test: $(TAP) - $(TAP) test/*.test.js +test: + $(NPM) test include ./Makefile.deps include ./Makefile.targ diff --git a/test/messages/del_request.test.js b/test/messages/del_request.test.js index ce55534..9b7d527 100644 --- a/test/messages/del_request.test.js +++ b/test/messages/del_request.test.js @@ -1,8 +1,9 @@ // Copyright 2011 Mark Cavage, Inc. All rights reserved. -var test = require('tap').test; var asn1 = require('asn1'); +var Logger = require('bunyan'); +var test = require('tap').test; ///--- Globals @@ -43,7 +44,9 @@ test('parse', function (t) { var ber = new BerWriter(); ber.writeString('cn=test', 0x4a); - var req = new DeleteRequest(); + var req = new DeleteRequest({ + log: new Logger({name: 'del_request.test.js'}) + }); var reader = new BerReader(ber.buffer); reader.readSequence(0x4a); t.ok(req.parse(reader, reader.length)); From 98193530428904d00838eefc75f1e4443d70483b Mon Sep 17 00:00:00 2001 From: Mark Cavage Date: Sat, 18 Feb 2012 14:58:40 -0800 Subject: [PATCH 24/24] Client refactoring. Cut reconnect logic and force users to listen for connect event. --- lib/client.js | 580 ++++++++++++++++++------------------------- test/laundry.test.js | 12 +- 2 files changed, 242 insertions(+), 350 deletions(-) diff --git a/lib/client.js b/lib/client.js index faddcd9..664ad53 100644 --- a/lib/client.js +++ b/lib/client.js @@ -42,7 +42,7 @@ var Parser = messages.Parser; var Filter = filters.Filter; var PresenceFilter = filters.PresenceFilter; - +var CMP_EXPECT = [errors.LDAP_COMPARE_TRUE, errors.LDAP_COMPARE_FALSE]; var MAX_MSGID = Math.pow(2, 31) - 1; @@ -115,143 +115,32 @@ function Client(options) { throw new TypeError('options.log must be an object'); if (!xor(options.url, options.socketPath)) - throw new TypeError('options.url ^ options.socketPath required'); + throw new TypeError('options.url ^ options.socketPath (String) required'); EventEmitter.call(this, options); - var self = this; - this.secure = false; - if (options.url) { - this.url = url.parse(options.url); - this.secure = this.url.secure; - } + if (options.url) + options.url = url.parse(options.url); this.connection = null; this.connectTimeout = options.connectTimeout || false; this.connectOptions = { - port: self.url ? self.url.port : options.socketPath, - host: self.url ? self.url.hostname : undefined, + port: options.url ? options.url.port : options.socketPath, + host: options.url ? options.url.hostname : undefined, socketPath: options.socketPath || undefined }; this.log = options.log; - this.reconnect = (typeof (options.reconnect) === 'number' ? - options.reconnect : 1000); - this.shutdown = false; + this.secure = options.url ? options.url.secure : false; this.timeout = options.timeout || false; + this.url = options.url || false; - return this.connect(function () {}); + // We'll emit a connect event when this is done + this.connect(); } util.inherits(Client, EventEmitter); module.exports = Client; -/** - * Connects this client, either at construct time, or after an unbind has - * been called. Under normal circumstances you don't need to call this method. - * - * @param {Function} callback invoked when `connect()` is done. - */ -Client.prototype.connect = function (callback) { - if (this.connection) - return callback(); - - var self = this; - var timer = false; - if (this.connectTimeout) { - timer = setTimeout(function () { - if (self.connection) - self.connection.destroy(); - - var err = new ConnectionError('timeout'); - self.emit('connectTimeout'); - return callback(err); - }, this.connectTimeout); - } - - this.connection = this._newConnection(); - - function reconnect() { - self.connection = null; - - if (self.reconnect) { - setTimeout(function () { - self.connect(function () {}); - }, self.reconnect); - } - } - - self.connection.on('close', function (had_err) { - self.emit('close', had_err); - reconnect(); - }); - - self.connection.on('connect', function () { - if (timer) - clearTimeout(timer); - - if (self._bindDN && self._credentials) - return self.bind(self._bindDN, self._credentials, function (err) { - if (err) { - self.log.error('Unable to bind(on(\'connect\')): %s', err.stack); - self.connection.end(); - } - - return callback(); - }); - - return callback(); - }); - - return false; -}; - - -/** - * Performs a simple authentication against the server. - * - * @param {String} name the DN to bind as. - * @param {String} credentials the userPassword associated with name. - * @param {Control} controls (optional) either a Control or [Control]. - * @param {Function} callback of the form f(err, res). - * @param {Socket} conn don't use this. Internal only (reconnects). - * @throws {TypeError} on invalid input. - */ -Client.prototype.bind = function (name, credentials, controls, callback, conn) { - if (typeof (name) !== 'string' && !(name instanceof dn.DN)) - throw new TypeError('name (string) required'); - if (typeof (credentials) !== 'string') - throw new TypeError('credentials (string) required'); - if (typeof (controls) === 'function') { - callback = controls; - controls = []; - } else { - controls = validateControls(controls); - } - if (typeof (callback) !== 'function') - throw new TypeError('callback (function) required'); - - - var self = this; - this.connect(function () { - var req = new BindRequest({ - name: name || '', - authentication: 'Simple', - credentials: credentials || '', - controls: controls - }); - - return self._send(req, [errors.LDAP_SUCCESS], function (err, res) { - if (!err) { // In case we need to reconnect later - self._bindDN = name; - self._credentials = credentials; - } - - return callback(err, res); - }, conn); - }); -}; - - /** * Sends an abandon request to the LDAP server. * @@ -263,7 +152,7 @@ Client.prototype.bind = function (name, credentials, controls, callback, conn) { * @param {Function} callback of the form f(err). * @throws {TypeError} on invalid input. */ -Client.prototype.abandon = function (messageID, controls, callback) { +Client.prototype.abandon = function abandon(messageID, controls, callback) { if (typeof (messageID) !== 'number') throw new TypeError('messageID (number) required'); if (typeof (controls) === 'function') { @@ -280,7 +169,7 @@ Client.prototype.abandon = function (messageID, controls, callback) { controls: controls }); - return this._send(req, 'abandon', callback); + return this._send(req, 'abandon', null, callback); }; @@ -297,7 +186,7 @@ Client.prototype.abandon = function (messageID, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.add = function (name, entry, controls, callback) { +Client.prototype.add = function add(name, entry, controls, callback) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (typeof (entry) !== 'object') @@ -339,7 +228,41 @@ Client.prototype.add = function (name, entry, controls, callback) { controls: controls }); - return this._send(req, [errors.LDAP_SUCCESS], callback); + return this._send(req, [errors.LDAP_SUCCESS], null, callback); +}; + + +/** + * Performs a simple authentication against the server. + * + * @param {String} name the DN to bind as. + * @param {String} credentials the userPassword associated with name. + * @param {Control} controls (optional) either a Control or [Control]. + * @param {Function} callback of the form f(err, res). + * @throws {TypeError} on invalid input. + */ +Client.prototype.bind = function bind(name, credentials, controls, callback) { + if (typeof (name) !== 'string' && !(name instanceof dn.DN)) + throw new TypeError('name (string) required'); + if (typeof (credentials) !== 'string') + throw new TypeError('credentials (string) required'); + if (typeof (controls) === 'function') { + callback = controls; + controls = []; + } else { + controls = validateControls(controls); + } + if (typeof (callback) !== 'function') + throw new TypeError('callback (function) required'); + + var req = new BindRequest({ + name: name || '', + authentication: 'Simple', + credentials: credentials || '', + controls: controls + }); + + return this._send(req, [errors.LDAP_SUCCESS], null, callback); }; @@ -353,7 +276,11 @@ Client.prototype.add = function (name, entry, controls, callback) { * @param {Function} callback of the form f(err, boolean, res). * @throws {TypeError} on invalid input. */ -Client.prototype.compare = function (name, attr, value, controls, callback) { +Client.prototype.compare = function compare(name, + attr, + value, + controls, + callback) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (typeof (attr) !== 'string') @@ -376,16 +303,12 @@ Client.prototype.compare = function (name, attr, value, controls, callback) { controls: controls }); - function _callback(err, res) { + return this._send(req, CMP_EXPECT, null, function (err, res) { if (err) return callback(err); return callback(null, (res.status === errors.LDAP_COMPARE_TRUE), res); - } - - return this._send(req, - [errors.LDAP_COMPARE_TRUE, errors.LDAP_COMPARE_FALSE], - _callback); + }); }; @@ -397,7 +320,7 @@ Client.prototype.compare = function (name, attr, value, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.del = function (name, controls, callback) { +Client.prototype.del = function del(name, controls, callback) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (typeof (controls) === 'function') { @@ -414,7 +337,7 @@ Client.prototype.del = function (name, controls, callback) { controls: controls }); - return this._send(req, [errors.LDAP_SUCCESS], callback); + return this._send(req, [errors.LDAP_SUCCESS], null, callback); }; @@ -431,7 +354,7 @@ Client.prototype.del = function (name, controls, callback) { * @param {Function} callback of the form f(err, value, res). * @throws {TypeError} on invalid input. */ -Client.prototype.exop = function (name, value, controls, callback) { +Client.prototype.exop = function exop(name, value, controls, callback) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (typeof (value) === 'function') { @@ -456,14 +379,12 @@ Client.prototype.exop = function (name, value, controls, callback) { controls: controls }); - function _callback(err, res) { + return this._send(req, [errors.LDAP_SUCCESS], null, function (err, res) { if (err) return callback(err); return callback(null, res.responseValue || '', res); - } - - return this._send(req, [errors.LDAP_SUCCESS], _callback); + }); }; @@ -476,7 +397,7 @@ Client.prototype.exop = function (name, value, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.modify = function (name, change, controls, callback) { +Client.prototype.modify = function modify(name, change, controls, callback) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (typeof (change) !== 'object') @@ -529,7 +450,7 @@ Client.prototype.modify = function (name, change, controls, callback) { controls: controls }); - return this._send(req, [errors.LDAP_SUCCESS], callback); + return this._send(req, [errors.LDAP_SUCCESS], null, callback); }; @@ -547,7 +468,10 @@ Client.prototype.modify = function (name, change, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.modifyDN = function (name, newName, controls, callback) { +Client.prototype.modifyDN = function modifyDN(name, + newName, + controls, + callback) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (typeof (newName) !== 'string') @@ -577,7 +501,7 @@ Client.prototype.modifyDN = function (name, newName, controls, callback) { req.newRdn = newDN; } - return this._send(req, [errors.LDAP_SUCCESS], callback); + return this._send(req, [errors.LDAP_SUCCESS], null, callback); }; @@ -604,7 +528,7 @@ Client.prototype.modifyDN = function (name, newName, controls, callback) { * @param {Function} callback of the form f(err, res). * @throws {TypeError} on invalid input. */ -Client.prototype.search = function (base, options, controls, callback) { +Client.prototype.search = function search(base, options, controls, callback) { if (typeof (base) !== 'string' && !(base instanceof dn.DN)) throw new TypeError('base (string) required'); if (Array.isArray(options) || (options instanceof Control)) { @@ -647,6 +571,7 @@ Client.prototype.search = function (base, options, controls, callback) { } } } + var req = new SearchRequest({ baseObject: typeof (base) === 'string' ? dn.parse(base) : base, scope: options.scope || 'base', @@ -659,31 +584,7 @@ Client.prototype.search = function (base, options, controls, callback) { controls: controls }); - - - if (!this.connection) - return callback(new ConnectionError('no connection')); - - var res = new EventEmitter(); - - // This is some whacky logic to account for the connection not being - // reconnected, and having thrown an error like "NotWriteable". Because - // the event emitter logic will never block, we'll end up returning from - // the event.on('error'), rather than "normally". - var done = false; - function errorIfNoConn(err) { - if (done) - return false; - - done = true; - return callback(err); - } - res.once('error', errorIfNoConn); - this._send(req, [errors.LDAP_SUCCESS], res); - - done = true; - res.removeListener('error', errorIfNoConn); - return callback(null, res); + return this._send(req, [errors.LDAP_SUCCESS], new EventEmitter(), callback); }; @@ -696,194 +597,81 @@ Client.prototype.search = function (base, options, controls, callback) { * @param {Function} callback of the form f(err). * @throws {TypeError} if you pass in callback as not a function. */ -Client.prototype.unbind = function (callback) { - if (callback && typeof (callback) !== 'function') - throw new TypeError('callback must be a function'); +Client.prototype.unbind = function unbind(callback) { if (!callback) - callback = function () { self.log.trace('disconnected'); }; + callback = function () {}; - var self = this; - this.reconnect = false; - this._bindDN = null; - this._credentials = null; + if (typeof (callback) !== 'function') + throw new TypeError('callback must be a function'); if (!this.connection) return callback(); var req = new UnbindRequest(); - return self._send(req, 'unbind', callback); + return this._send(req, 'unbind', null, callback); }; - -Client.prototype._send = function (message, expect, callback, connection) { - assert.ok(message); - assert.ok(expect); - assert.ok(callback); - - var conn = connection || this.connection; - +/** + * Connects this client, either at construct time, or after an unbind has + * been called. Under normal circumstances you don't need to call this method. + * + * @param {Function} (optional) callback invoked when `connect` is emitted. + */ +Client.prototype.connect = function connect(callback) { + var c = null; + var log = this.log; + var opts = this.connectOptions; + var proto = this.secure ? tls : net; var self = this; - var timer; + var timer = false; - function closeConn(err) { + c = proto.connect(opts.port, opts.host); + + if (this.connectTimeout) { + timer = setTimeout(function () { + c.destroy(); + + self.emit('connectTimeout', new ConnectionError('timeout')); + }, this.connectTimeout); + } + + if (typeof (c.setKeepAlive) !== 'function') { + c.setKeepAlive = function setKeepAlive(enable, delay) { + return c.socket ? c.socket.setKeepAlive(enable, delay) : false; + }; + } + + c.ldap = { + id: self.url ? self.url.href : opts.socketPath, + messageID: 0, + messages: {}, + get nextMessageID() { + if (++c.ldap.messageID >= MAX_MSGID) + c.ldap.messageID = 1; + + return c.ldap.messageID; + }, + parser: new Parser({ + log: self.log + }) + }; + + c.on('connect', function () { if (timer) clearTimeout(timer); - err = err || new ConnectionError('no connection'); + assert.ok(c.ldap); - if (typeof (callback) === 'function') { - callback(err); - } else { - callback.emit('error', err); - } + c.ldap.id += c.fd ? (':' + c.fd) : ''; - if (conn) - conn.destroy(); - } - - if (!conn) - return closeConn(); - - // Now set up the callback in the messages table - message.messageID = conn.ldap.nextMessageID; - if (expect !== 'abandon') { - conn.ldap.messages[message.messageID] = function (res) { - if (timer) - clearTimeout(timer); - - if (self.log.debug()) - self.log.debug({res: res.json}, '%s: response received', conn.ldap.id); - - var err = null; - - if (res instanceof LDAPResult) { - delete conn.ldap.messages[message.messageID]; - - if (expect.indexOf(res.status) === -1) { - err = errors.getError(res); - if (typeof (callback) === 'function') - return callback(err); - - return callback.emit('error', err); - } - - if (typeof (callback) === 'function') - return callback(null, res); - - callback.emit('end', res); - } else if (res instanceof SearchEntry) { - assert.ok(callback instanceof EventEmitter); - callback.emit('searchEntry', res); - - } else if (res instanceof SearchReference) { - assert.ok(callback instanceof EventEmitter); - callback.emit('searchReference', res); - - } else if (res instanceof Error) { - if (typeof (callback) === 'function') - return callback(res); - - assert.ok(callback instanceof EventEmitter); - callback.emit('error', res); - } else { - delete conn.ldap.messages[message.messageID]; - - err = new errors.ProtocolError(res.type); - if (typeof (callback) === 'function') - return callback(err); - - callback.emit('error', err); - } - - return false; - }; - } - - // If there's a user specified timeout, pick that up - if (this.timeout) { - timer = setTimeout(function () { - self.emit('timeout', message); - if (conn.ldap.messages[message.messageID]) - conn.ldap.messages[message.messageID](new LDAPResult({ - status: 80, // LDAP_OTHER - errorMessage: 'request timeout (client interrupt)' - })); - }, this.timeout); - } - - try { - // Note if this was an unbind, we just go ahead and end, since there - // will never be a response - var _writeCb = null; - if (expect === 'abandon') { - _writeCb = function () { - return callback(); - }; - } else if (expect === 'unbind') { - _writeCb = function () { - conn.unbindMessageID = message.id; - conn.end(); - }; - } - - // Finally send some data - if (this.log.debug()) - this.log.debug({msg: message.json}, '%s: sending request', conn.ldap.id); - return conn.write(message.toBer(), _writeCb); - } catch (e) { - return closeConn(e); - } -}; - - -Client.prototype._newConnection = function () { - var c; - var connectOpts = this.connectOptions; - var log = this.log; - var self = this; - - if (this.secure) { - c = tls.connect(connectOpts.port, connectOpts.host, function () { - if (log.trace()) - log.trace('%s connect event', c.ldap.id); - - c.ldap.connected = true; - c.ldap.id += c.fd ? (':' + c.fd) : ''; - c.emit('connect', c.ldap.id); - }); - c.setKeepAlive = function (enable, delay) { - return c.socket.setKeepAlive(enable, delay); - }; - } else { - c = net.createConnection(connectOpts.port, connectOpts.host); - } - assert.ok(c); - - c.parser = new Parser({ - log: self.log - }); - - // Wrap the events - c.ldap = { - id: self.url ? self.url.hostname : connectOpts.socketPath, - messageID: 0, - messages: {} - }; - - c.ldap.__defineGetter__('nextMessageID', function () { - if (++c.ldap.messageID >= MAX_MSGID) - c.ldap.messageID = 1; - return c.ldap.messageID; - }); - - c.on('connect', function () { if (log.trace()) log.trace('%s connect event', c.ldap.id); - c.ldap.connected = true; - c.ldap.id += c.fd ? (':' + c.fd) : ''; - self.emit('connect', c.ldap.id); + self.connection = c; + self.emit('connect', c); + + return (typeof (callback) === 'function' ? callback(null, c) : false); }); c.on('end', function () { @@ -893,6 +681,8 @@ Client.prototype._newConnection = function () { c.end(); }); + // On close we have to walk the outstanding messages and go invoke their + // callback with an error c.on('close', function (had_err) { if (log.trace()) log.trace('%s close event had_err=%s', c.ldap.id, had_err ? 'yes' : 'no'); @@ -918,8 +708,8 @@ Client.prototype._newConnection = function () { delete c.ldap.messages[msgid]; } + delete c.ldap.parser; delete c.ldap; - delete c.parser; return false; }); }); @@ -946,25 +736,24 @@ Client.prototype._newConnection = function () { if (log.trace()) log.trace('%s data event: %s', c.ldap.id, util.inspect(data)); - c.parser.write(data); + c.ldap.parser.write(data); }); // The "router" - c.parser.on('message', function (message) { + c.ldap.parser.on('message', function (message) { message.connection = c; var callback = c.ldap.messages[message.messageID]; if (!callback) { - log.error('%s: unsolicited message: %j', c.ldap.id, message.json); + log.error({message: message.json}, '%s: unsolicited message', c.ldap.id); return false; } return callback(message); }); - c.parser.on('error', function (err) { - if (log.trace()) - log.trace({err: err}, '%s error event', c.ldap.id); + c.ldap.parser.on('error', function (err) { + log.debug({err: err}, '%s parser error event', c.ldap.id); if (self.listeners('error').length) self.emit('error', err); @@ -974,3 +763,106 @@ Client.prototype._newConnection = function () { return c; }; + + +Client.prototype._send = function _send(message, expect, emitter, callback) { + assert.ok(message); + assert.ok(expect); + assert.ok(typeof (emitter) !== undefined); + assert.ok(callback); + + var conn = this.connection; + var self = this; + var timer = false; + + if (!conn) + return callback(new ConnectionError('no socket')); + + message.messageID = conn.ldap.nextMessageID; + conn.ldap.messages[message.messageID] = function messageCallback(res) { + if (timer) + clearTimeout(timer); + + if (expect === 'abandon') + return callback(null); + + if (self.log.debug()) + self.log.debug({res: res.json}, '%s: response received', conn.ldap.id); + + var err = null; + + if (res instanceof LDAPResult) { + delete conn.ldap.messages[message.messageID]; + + if (expect.indexOf(res.status) === -1) { + err = errors.getError(res); + if (emitter) + return emitter.emit('error', err); + + return callback(err); + } + + if (emitter) + return emitter.emit('end', res); + + return callback(null, res); + } else if (res instanceof SearchEntry || res instanceof SearchReference) { + assert.ok(emitter); + var event = res.constructor.name; + event = event[0].toLowerCase() + event.slice(1); + return emitter.emit(event, res); + } else if (res instanceof Error) { + if (emitter) + return emitter.emit('error', res); + + return callback(res); + } + + delete conn.ldap.messages[message.messageID]; + err = new errors.ProtocolError(res.type); + + if (emitter) + return emitter.emit('error', err); + + return callback(err); + }; + + // If there's a user specified timeout, pick that up + if (this.timeout) { + timer = setTimeout(function () { + self.emit('timeout', message); + if (conn.ldap.messages[message.messageID]) { + conn.ldap.messages[message.messageID](new LDAPResult({ + status: 80, // LDAP_OTHER + errorMessage: 'request timeout (client interrupt)' + })); + } + }, this.timeout); + } + + try { + // Finally send some data + if (this.log.debug()) + this.log.debug({msg: message.json}, '%s: sending request', conn.ldap.id); + + return conn.write(message.toBer(), function writeCallback() { + if (expect === 'abandon') { + return callback(null); + } else if (expect === 'unbind') { + conn.unbindMessageID = message.id; + conn.end(); + } else if (emitter) { + return callback(null, emitter); + } + return false; + }); + + } catch (e) { + if (timer) + clearTimeout(timer); + + conn.destroy(); + delete self.connection; + return callback(e); + } +}; diff --git a/test/laundry.test.js b/test/laundry.test.js index e44a394..0bdc47e 100644 --- a/test/laundry.test.js +++ b/test/laundry.test.js @@ -119,12 +119,12 @@ test('GH-55 Client emits connect multiple times', function (t) { c.on('connect', function (socket) { t.ok(socket); count++; - }); - c.bind('cn=root', 'secret', function (err, res) { - t.ifError(err); - c.unbind(function () { - t.equal(count, 1); - t.end(); + c.bind('cn=root', 'secret', function (err, res) { + t.ifError(err); + c.unbind(function () { + t.equal(count, 1); + t.end(); + }); }); }); });