From c5ccafd436ac8d9b51e9be0b9baf2a8e997c6df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20S=C3=BCssemilch=20Poulain?= Date: Fri, 16 May 2014 17:10:24 +0200 Subject: [PATCH 1/3] Server Side Sorting control --- lib/controls/index.js | 10 +- lib/controls/server_side_sorting_control.js | 117 ++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 lib/controls/server_side_sorting_control.js diff --git a/lib/controls/index.js b/lib/controls/index.js index d2d7f23..4157d5f 100644 --- a/lib/controls/index.js +++ b/lib/controls/index.js @@ -7,6 +7,7 @@ var EntryChangeNotificationControl = require('./entry_change_notification_control'); var PersistentSearchControl = require('./persistent_search_control'); var PagedResultsControl = require('./paged_results_control'); +var ServerSideSortingControl = require('./server_side_sorting_control.js'); @@ -57,6 +58,12 @@ module.exports = { value: value }); break; + case ServerSideSortingControl.OID: + control = new ServerSideSortingControl({ + critical: critical, + value: value + }); + break; default: control = new Control({ type: type, @@ -72,5 +79,6 @@ module.exports = { Control: Control, EntryChangeNotificationControl: EntryChangeNotificationControl, PagedResultsControl: PagedResultsControl, - PersistentSearchControl: PersistentSearchControl + PersistentSearchControl: PersistentSearchControl, + ServerSideSortingControl: ServerSideSortingControl }; diff --git a/lib/controls/server_side_sorting_control.js b/lib/controls/server_side_sorting_control.js new file mode 100644 index 0000000..995a369 --- /dev/null +++ b/lib/controls/server_side_sorting_control.js @@ -0,0 +1,117 @@ +var assert = require('assert'); +var util = require('util'); + +var asn1 = require('asn1'); + +var Control = require('./control'); + + + +///--- Globals + +var BerReader = asn1.BerReader; +var BerWriter = asn1.BerWriter; + + + +///--- API + +function ServerSideSortingControl(options) { + if (!options) + options = {}; + + options.type = ServerSideSortingControl.OID; + if (options.value) { + if (Buffer.isBuffer(options.value)) { + this.parse(options.value); + } else if (Array.isArray(options.value)) { + for (var i = 0; i < options.value.length; i++) { + if (!typeof (options.value[i]) === 'object') { + throw new TypeError('Elements of options.value must be Objects'); + } else if (!options.value[i].hasOwnProperty('attributeType')) { + throw new Error('Missing required key: attributeType'); + } + } + this._value = options.value; + } else if (typeof (options.value) === 'object') { + if (!options.value.hasOwnProperty('attributeType')) { + throw new Error('Missing required key: attributeType'); + } + this._value = options.value; + } else { + throw new TypeError('options.value must be a Buffer, Array or Object'); + } + options.value = null; + } + Control.call(this, options); + + var self = this; + this.__defineGetter__('value', function () { + return self._value || {}; + }); +} +util.inherits(ServerSideSortingControl, Control); +module.exports = ServerSideSortingControl; + + +ServerSideSortingControl.prototype.parse = function parse(buffer) { + assert.ok(buffer); + + var ber = new BerReader(buffer); + if (ber.readSequence()) { + this._value = {}; + this._value.sortResult = ber.readInt(); + this._value.attributeType = ber.readString(asn1.Ber.OctetString, true); + //readString returns '' instead of a zero-length buffer + if (!this._value.attributeType) + this._value.attributeType = new Buffer(0); + + return true; + } + + return false; +}; + + +ServerSideSortingControl.prototype._toBer = function (ber) { + assert.ok(ber); + + if (!this._value) + return; + + var writer = new BerWriter(); + writer.startSequence(0x30); + + if (Array.isArray(this.value)) { + for (var i = 0; i < this.value.length; i++) { + this._sortKeyListItemToBer(writer, this.value[i]); + } + } else if (typeof (this.value) === 'object') { + this._sortKeyListItemToBer(writer, this.value); + } + + writer.endSequence(); + ber.writeBuffer(writer.buffer, 0x04); +}; + + +ServerSideSortingControl.prototype._json = function (obj) { + obj.controlValue = this.value; + return obj; +}; + +ServerSideSortingControl.prototype._sortKeyListItemToBer = function(writer, obj) { + writer.startSequence(0x30); + if (obj.attributeType) { + writer.writeString(obj.attributeType, asn1.Ber.OctetString); + } + if (obj.orderingRule) { + writer.writeString(obj.orderingRule, 0x80); + } + if (obj.reverseOrder) { + writer.writeBoolean(obj.reverseOrder, 0x81); + } + writer.endSequence(); +}; + +ServerSideSortingControl.OID = '1.2.840.113556.1.4.473'; From c1af9a8814a42bbee59bcd547ebc2fa1d53690b8 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 26 May 2014 21:12:14 +0000 Subject: [PATCH 2/3] Server side sorting control tests --- .../server_side_sorting_control_test.js | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 test/controls/server_side_sorting_control_test.js diff --git a/test/controls/server_side_sorting_control_test.js b/test/controls/server_side_sorting_control_test.js new file mode 100644 index 0000000..9cca748 --- /dev/null +++ b/test/controls/server_side_sorting_control_test.js @@ -0,0 +1,82 @@ + +var test = require('tap').test; + +var asn1 = require('asn1'); + +var BerReader = asn1.BerReader; +var BerWriter = asn1.BerWriter; +var getControl; +var ServerSideSortingControl; + +function bufferEqual(t, a, b) { + t.equal(a.toString('hex'), b.toString('hex')); +} + + +///--- Tests + + +test('load library', function (t) { + ServerSideSortingControl = + require('../../lib').ServerSideSortingControl; + t.ok(ServerSideSortingControl); + getControl = require('../../lib').getControl; + t.ok(getControl); + t.end(); +}); + + +test('new no args', function (t) { + t.ok(new ServerSideSortingControl()); + t.end(); +}); + + +test('new with args', function (t) { + var c = new ServerSideSortingControl({ + type: '1.2.840.113556.1.4.473', + criticality: true, + value: { + attributeType: 'sn' + } + }); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.473'); + t.ok(c.criticality); + t.equal(c.value.attributeType, 'sn'); + + var writer = new BerWriter(); + c.toBer(writer); + var reader = new BerReader(writer.buffer); + var sssc = getControl(reader); + t.ok(sssc); + console.log('sssc', sssc.value); + t.equal(sssc.type, '1.2.840.113556.1.4.473'); + t.ok(sssc.criticality); + t.equal(sssc.value.attributeType, 'sn'); + bufferEqual(t, sssc.value.cookie, new Buffer(['sn'])); + + t.end(); +}); + +test('tober', function (t) { + var sssc = new ServerSideSortingControl({ + type: '1.2.840.113556.1.4.473', + criticality: true, + value: { + attributeType: 'sn' + } + }); + + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.473'); + t.ok(c.criticality); + t.equal(c.value.attributeType, 'sn'); + bufferEqual(t, c.value.cookie, new Buffer(0)); + + t.end(); +}); From b742e286dbc87f6c78fa5ee6d8b7b2c70bb6eb15 Mon Sep 17 00:00:00 2001 From: = Date: Fri, 30 May 2014 20:57:06 +0000 Subject: [PATCH 3/3] Fixed parse method and added some tests --- lib/controls/server_side_sorting_control.js | 34 ++++++++--- .../server_side_sorting_control_test.js | 59 ++++++++++++------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/lib/controls/server_side_sorting_control.js b/lib/controls/server_side_sorting_control.js index 995a369..0f6308a 100644 --- a/lib/controls/server_side_sorting_control.js +++ b/lib/controls/server_side_sorting_control.js @@ -58,13 +58,18 @@ ServerSideSortingControl.prototype.parse = function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); - if (ber.readSequence()) { - this._value = {}; - this._value.sortResult = ber.readInt(); - this._value.attributeType = ber.readString(asn1.Ber.OctetString, true); - //readString returns '' instead of a zero-length buffer - if (!this._value.attributeType) - this._value.attributeType = new Buffer(0); + + if (ber.readSequence(0x30)) { + this._value = []; + + while (ber.readSequence(0x30)) { + var sortKeyListItem = this._parseSortKeyListItem(ber) + this._value.push(sortKeyListItem); + } + + if (this._value.length == 1) { + this._value = this._value[0]; + } return true; } @@ -114,4 +119,19 @@ ServerSideSortingControl.prototype._sortKeyListItemToBer = function(writer, obj) writer.endSequence(); }; +ServerSideSortingControl.prototype._parseSortKeyListItem = function(reader) { + var sortKeyListItem = {}; + sortKeyListItem.attributeType = reader.readString(asn1.Ber.OctetString); + + if (reader.peek() == 0x80) { + sortKeyListItem.orderingRule = reader.readString(0x80); + } + + if (reader.peek() == 0x81) { + sortKeyListItem.reverseOrder = (reader._readTag(0x81) === 0 ? false : true); + } + + return sortKeyListItem; +}; + ServerSideSortingControl.OID = '1.2.840.113556.1.4.473'; diff --git a/test/controls/server_side_sorting_control_test.js b/test/controls/server_side_sorting_control_test.js index 9cca748..dc28a75 100644 --- a/test/controls/server_side_sorting_control_test.js +++ b/test/controls/server_side_sorting_control_test.js @@ -8,11 +8,6 @@ var BerWriter = asn1.BerWriter; var getControl; var ServerSideSortingControl; -function bufferEqual(t, a, b) { - t.equal(a.toString('hex'), b.toString('hex')); -} - - ///--- Tests @@ -45,28 +40,18 @@ test('new with args', function (t) { t.ok(c.criticality); t.equal(c.value.attributeType, 'sn'); - var writer = new BerWriter(); - c.toBer(writer); - var reader = new BerReader(writer.buffer); - var sssc = getControl(reader); - t.ok(sssc); - console.log('sssc', sssc.value); - t.equal(sssc.type, '1.2.840.113556.1.4.473'); - t.ok(sssc.criticality); - t.equal(sssc.value.attributeType, 'sn'); - bufferEqual(t, sssc.value.cookie, new Buffer(['sn'])); - t.end(); }); -test('tober', function (t) { +test('tober - object', function (t) { var sssc = new ServerSideSortingControl({ type: '1.2.840.113556.1.4.473', criticality: true, value: { - attributeType: 'sn' - } - }); + attributeType: 'sn', + orderingRule: 'caseIgnoreOrderingMatch', + reverseOrder: true + }}); var ber = new BerWriter(); sssc.toBer(ber); @@ -76,7 +61,39 @@ test('tober', function (t) { t.equal(c.type, '1.2.840.113556.1.4.473'); t.ok(c.criticality); t.equal(c.value.attributeType, 'sn'); - bufferEqual(t, c.value.cookie, new Buffer(0)); + t.equal(c.value.orderingRule, 'caseIgnoreOrderingMatch'); + t.equal(c.value.reverseOrder, true); + + t.end(); +}); + +test('tober - array', function (t) { + var sssc = new ServerSideSortingControl({ + type: '1.2.840.113556.1.4.473', + criticality: true, + value: [{ + attributeType: 'sn', + orderingRule: 'caseIgnoreOrderingMatch', + reverseOrder: true + }, + { + attributeType: 'givenName', + orderingRule: 'caseIgnoreOrderingMatch' + }] + }); + + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.473'); + t.ok(c.criticality); + t.equal(c.value[0].attributeType, 'sn'); + t.equal(c.value[0].orderingRule, 'caseIgnoreOrderingMatch'); + t.equal(c.value[0].reverseOrder, true); + t.equal(c.value[1].attributeType, 'givenName'); + t.equal(c.value[1].orderingRule, 'caseIgnoreOrderingMatch'); t.end(); });