First commit
This commit is contained in:
88
node_modules/@ldapjs/controls/lib/control.js
generated
vendored
Normal file
88
node_modules/@ldapjs/controls/lib/control.js
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
'use strict'
|
||||
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
|
||||
/**
|
||||
* Baseline LDAP control object. Implements
|
||||
* https://tools.ietf.org/html/rfc4511#section-4.1.11
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class Control {
|
||||
/**
|
||||
* @typedef {object} ControlParams
|
||||
* @property {string} [type=''] The dotted decimal control type value.
|
||||
* @property {boolean} [criticality=false] Criticality value for the control.
|
||||
* @property {string|Buffer} [value] The value for the control. If this is
|
||||
* a `string` then it will be written as-is. If it is an instance of `Buffer`
|
||||
* then it will be written by `value.toString()` when generating a BER
|
||||
* instance.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a new baseline LDAP control.
|
||||
*
|
||||
* @param {ControlParams} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
const opts = Object.assign({ type: '', criticality: false, value: null }, options)
|
||||
this.type = opts.type
|
||||
this.criticality = opts.criticality
|
||||
this.value = opts.value
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag] () {
|
||||
return 'LdapControl'
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the control into a plain JavaScript object that can be passed
|
||||
* to the constructor as an options object. If an instance has a `_pojo(obj)`
|
||||
* method then the built object will be sent to that method and the resulting
|
||||
* mutated object returned.
|
||||
*
|
||||
* @returns {object} A plain JavaScript object that represents an LDAP control.
|
||||
*/
|
||||
get pojo () {
|
||||
const obj = {
|
||||
type: this.type,
|
||||
value: this.value,
|
||||
criticality: this.criticality
|
||||
}
|
||||
|
||||
if (typeof this._pojo === 'function') {
|
||||
this._pojo(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the instance into a [BER](http://luca.ntop.org/Teaching/Appunti/asn1.html)
|
||||
* representation.
|
||||
*
|
||||
* @param {BerWriter} [ber] An empty `BerWriter` instance to populate.
|
||||
*
|
||||
* @returns {object} A BER object.
|
||||
*/
|
||||
toBer (ber = new BerWriter()) {
|
||||
ber.startSequence()
|
||||
ber.writeString(this.type || '')
|
||||
ber.writeBoolean(this.criticality)
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (typeof (this._toBer) === 'function') {
|
||||
this._toBer(ber)
|
||||
} else if (this.value !== undefined) {
|
||||
if (typeof this.value === 'string') {
|
||||
ber.writeString(this.value)
|
||||
} else if (Buffer.isBuffer(this.value)) {
|
||||
ber.writeString(this.value.toString())
|
||||
}
|
||||
}
|
||||
|
||||
ber.endSequence()
|
||||
return ber
|
||||
}
|
||||
}
|
||||
module.exports = Control
|
||||
159
node_modules/@ldapjs/controls/lib/control.test.js
generated
vendored
Normal file
159
node_modules/@ldapjs/controls/lib/control.test.js
generated
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
const Control = require('./control')
|
||||
|
||||
tap.test('constructor', t => {
|
||||
t.test('new no args', function (t) {
|
||||
t.ok(new Control())
|
||||
t.equal(Object.prototype.toString.call(new Control()), '[object LdapControl]')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('new with args', function (t) {
|
||||
const c = new Control({
|
||||
type: '2.16.840.1.113730.3.4.2',
|
||||
criticality: true
|
||||
})
|
||||
t.ok(c)
|
||||
t.equal(c.type, '2.16.840.1.113730.3.4.2')
|
||||
t.ok(c.criticality)
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('pojo', t => {
|
||||
t.test('passes through _pojo', async t => {
|
||||
class Foo extends Control {
|
||||
_pojo (obj) {
|
||||
obj.foo = 'foo'
|
||||
}
|
||||
}
|
||||
const control = new Foo()
|
||||
t.strictSame(control.pojo, {
|
||||
type: '',
|
||||
value: null,
|
||||
criticality: false,
|
||||
foo: 'foo'
|
||||
})
|
||||
})
|
||||
|
||||
t.test('returns basic object', async t => {
|
||||
const control = new Control({ type: '1.2.3', criticality: false, value: 'foo' })
|
||||
t.strictSame(control.pojo, {
|
||||
type: '1.2.3',
|
||||
value: 'foo',
|
||||
criticality: false
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('converts empty instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString('')
|
||||
target.writeBoolean(false)
|
||||
target.endSequence()
|
||||
|
||||
const control = new Control()
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString('2.16.840.1.113730.3.4.2')
|
||||
target.writeBoolean(true)
|
||||
target.writeString('foo')
|
||||
target.endSequence()
|
||||
|
||||
const control = new Control({
|
||||
type: '2.16.840.1.113730.3.4.2',
|
||||
criticality: true,
|
||||
value: Buffer.from('foo', 'utf8')
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts instance to BER (side effect manner)', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString('2.16.840.1.113730.3.4.2')
|
||||
target.writeBoolean(true)
|
||||
target.writeString('foo')
|
||||
target.endSequence()
|
||||
|
||||
const control = new Control({
|
||||
type: '2.16.840.1.113730.3.4.2',
|
||||
criticality: true,
|
||||
value: Buffer.from('foo', 'utf8')
|
||||
})
|
||||
const ber = new BerWriter()
|
||||
control.toBer(ber)
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts instance to BER with string value', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString('2.16.840.1.113730.3.4.2')
|
||||
target.writeBoolean(true)
|
||||
target.writeString('foo')
|
||||
target.endSequence()
|
||||
|
||||
const control = new Control({
|
||||
type: '2.16.840.1.113730.3.4.2',
|
||||
criticality: true,
|
||||
value: 'foo'
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('ignores unrecognized value', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString('2.16.840.1.113730.3.4.2')
|
||||
target.writeBoolean(true)
|
||||
target.writeBoolean(false)
|
||||
target.endSequence()
|
||||
|
||||
const control = new Control({
|
||||
type: '2.16.840.1.113730.3.4.2',
|
||||
criticality: true,
|
||||
value: false
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.not(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('passes through _toBer', async t => {
|
||||
t.plan(2)
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString('')
|
||||
target.writeBoolean(false)
|
||||
target.endSequence()
|
||||
|
||||
const control = new Control()
|
||||
control._toBer = (ber) => t.ok(ber)
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
107
node_modules/@ldapjs/controls/lib/controls/entry-change-notification-control.js
generated
vendored
Normal file
107
node_modules/@ldapjs/controls/lib/controls/entry-change-notification-control.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
'use strict'
|
||||
|
||||
const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const Control = require('../control')
|
||||
|
||||
/**
|
||||
* @typedef {object} EntryChangeNotificationControlValue
|
||||
* @property {number} changeType One of 1 (add), 2 (delete), 4 (modify),
|
||||
* or 8 (modifyDN).
|
||||
* @property {string} previousDN Only set when operation is a modifyDN op.
|
||||
* @property {number} changeNumber
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* https://datatracker.ietf.org/doc/html/draft-ietf-ldapext-psearch-03.txt#section-5
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class EntryChangeNotificationControl extends Control {
|
||||
static OID = '2.16.840.1.113730.3.4.7'
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} EntryChangeNotificationParams
|
||||
* @property {EntryChangeNotificationControlValue | Buffer} [value]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new persistent search control.
|
||||
*
|
||||
* @param {EntryChangeNotificationParams} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
options.type = EntryChangeNotificationControl.OID
|
||||
super(options)
|
||||
|
||||
this._value = {
|
||||
changeType: 4
|
||||
}
|
||||
|
||||
if (hasOwn(options, 'value') === false) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(options.value)) {
|
||||
this.#parse(options.value)
|
||||
} else if (isObject(options.value)) {
|
||||
this._value = options.value
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer or Object')
|
||||
}
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (obj) {
|
||||
this._value = Object.assign({}, this._value, obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a BER buffer that represents a
|
||||
* {@link EntryChangeNotificationControlValue}, read that buffer into the
|
||||
* current instance.
|
||||
*/
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
/* istanbul ignore else */
|
||||
if (ber.readSequence()) {
|
||||
this._value = {
|
||||
changeType: ber.readInt()
|
||||
}
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (this._value.changeType === 8) {
|
||||
// If the operation was moddn, then parse the optional previousDN attr.
|
||||
this._value.previousDN = ber.readString()
|
||||
}
|
||||
|
||||
this._value.changeNumber = ber.readInt()
|
||||
}
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence()
|
||||
writer.writeInt(this._value.changeType)
|
||||
if (this._value.previousDN) { writer.writeString(this._value.previousDN) }
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this._value, 'changeNumber')) {
|
||||
writer.writeInt(parseInt(this._value.changeNumber, 10))
|
||||
}
|
||||
writer.endSequence()
|
||||
|
||||
ber.writeBuffer(writer.buffer, 0x04)
|
||||
return ber
|
||||
}
|
||||
|
||||
_updatePlainObject (obj) {
|
||||
obj.controlValue = this.value
|
||||
return obj
|
||||
}
|
||||
}
|
||||
module.exports = EntryChangeNotificationControl
|
||||
133
node_modules/@ldapjs/controls/lib/controls/entry-change-notification-control.test.js
generated
vendored
Normal file
133
node_modules/@ldapjs/controls/lib/controls/entry-change-notification-control.test.js
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
const ECNC = require('./entry-change-notification-control')
|
||||
const Control = require('../control')
|
||||
|
||||
tap.test('contructor', t => {
|
||||
t.test('new no args', async t => {
|
||||
const control = new ECNC()
|
||||
t.ok(control)
|
||||
t.type(control, ECNC)
|
||||
t.type(control, Control)
|
||||
t.equal(control.type, ECNC.OID)
|
||||
t.same(control.value, {
|
||||
changeType: 4
|
||||
})
|
||||
})
|
||||
|
||||
t.test('new with args', async t => {
|
||||
const control = new ECNC({
|
||||
type: '2.16.840.1.113730.3.4.7',
|
||||
criticality: true,
|
||||
value: {
|
||||
changeType: 1
|
||||
}
|
||||
})
|
||||
t.ok(control)
|
||||
t.equal(control.type, '2.16.840.1.113730.3.4.7')
|
||||
t.ok(control.criticality)
|
||||
t.same(control.value, {
|
||||
changeType: 1
|
||||
})
|
||||
})
|
||||
|
||||
t.test('with value buffer', async t => {
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(8)
|
||||
value.writeString('dn=foo')
|
||||
value.writeInt(42)
|
||||
value.endSequence()
|
||||
|
||||
const control = new ECNC({ value: value.buffer })
|
||||
t.same(control.value, {
|
||||
changeType: 8,
|
||||
previousDN: 'dn=foo',
|
||||
changeNumber: 42
|
||||
})
|
||||
})
|
||||
|
||||
t.test('throws for bad value', async t => {
|
||||
t.throws(() => new ECNC({ value: 42 }))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('pojo', t => {
|
||||
t.test('adds control value', async t => {
|
||||
const control = new ECNC({
|
||||
value: {
|
||||
changeType: 8,
|
||||
previousDN: 'dn=foo',
|
||||
changeNumber: 42
|
||||
}
|
||||
})
|
||||
t.strictSame(control.pojo, {
|
||||
type: ECNC.OID,
|
||||
criticality: false,
|
||||
value: {
|
||||
changeType: 8,
|
||||
previousDN: 'dn=foo',
|
||||
changeNumber: 42
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('converts empty instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(ECNC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(4)
|
||||
// value.writeInt(0)
|
||||
value.endSequence()
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new ECNC()
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts instance with full values to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(ECNC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(8)
|
||||
value.writeString('dn=foo')
|
||||
value.writeInt(42)
|
||||
value.endSequence()
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new ECNC({
|
||||
value: {
|
||||
changeType: 8,
|
||||
previousDN: 'dn=foo',
|
||||
changeNumber: 42
|
||||
}
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
103
node_modules/@ldapjs/controls/lib/controls/paged-results-control.js
generated
vendored
Normal file
103
node_modules/@ldapjs/controls/lib/controls/paged-results-control.js
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
'use strict'
|
||||
|
||||
const { Ber, BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const Control = require('../control')
|
||||
|
||||
/**
|
||||
* @typedef {object} PagedResultsControlValue
|
||||
* @property {number} size The requested page size from a client, or the result
|
||||
* set size estimate from the server.
|
||||
* @property {Buffer} cookie Identifier for the result set.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* https://datatracker.ietf.org/doc/html/rfc2696#section-2
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class PagedResultsControl extends Control {
|
||||
static OID = '1.2.840.113556.1.4.319'
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} PagedResultsParams
|
||||
* @property {PagedResultsControlValue | Buffer} [value]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new paged results control.
|
||||
*
|
||||
* @param {PagedResultsParams} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
options.type = PagedResultsControl.OID
|
||||
super(options)
|
||||
|
||||
this._value = {
|
||||
size: 0,
|
||||
cookie: Buffer.alloc(0)
|
||||
}
|
||||
|
||||
if (hasOwn(options, 'value') === false) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(options.value)) {
|
||||
this.#parse(options.value)
|
||||
} else if (isObject(options.value)) {
|
||||
this.value = options.value
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer or Object')
|
||||
}
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (obj) {
|
||||
this._value = Object.assign({}, this._value, obj)
|
||||
if (typeof this._value.cookie === 'string') {
|
||||
this._value.cookie = Buffer.from(this._value.cookie)
|
||||
}
|
||||
}
|
||||
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (ber.readSequence()) {
|
||||
this._value = {}
|
||||
this._value.size = ber.readInt()
|
||||
this._value.cookie = ber.readString(Ber.OctetString, true)
|
||||
// readString returns '' instead of a zero-length buffer
|
||||
if (!this._value.cookie) {
|
||||
this._value.cookie = Buffer.alloc(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence()
|
||||
writer.writeInt(this._value.size)
|
||||
if (this._value.cookie && this._value.cookie.length > 0) {
|
||||
writer.writeBuffer(this._value.cookie, Ber.OctetString)
|
||||
} else {
|
||||
// writeBuffer rejects zero-length buffers
|
||||
writer.writeString('')
|
||||
}
|
||||
writer.endSequence()
|
||||
|
||||
ber.writeBuffer(writer.buffer, Ber.OctetString)
|
||||
return ber
|
||||
}
|
||||
|
||||
_updatePlainObject (obj) {
|
||||
obj.controlValue = this.value
|
||||
return obj
|
||||
}
|
||||
}
|
||||
module.exports = PagedResultsControl
|
||||
139
node_modules/@ldapjs/controls/lib/controls/paged-results-control.test.js
generated
vendored
Normal file
139
node_modules/@ldapjs/controls/lib/controls/paged-results-control.test.js
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
const PSC = require('./paged-results-control')
|
||||
const Control = require('../control')
|
||||
|
||||
tap.test('contructor', t => {
|
||||
t.test('new no args', async t => {
|
||||
const control = new PSC()
|
||||
t.ok(control)
|
||||
t.type(control, PSC)
|
||||
t.type(control, Control)
|
||||
t.equal(control.type, PSC.OID)
|
||||
t.equal(control.value.size, 0)
|
||||
t.equal(Buffer.alloc(0).compare(control.value.cookie), 0)
|
||||
})
|
||||
|
||||
t.test('new with args', async t => {
|
||||
const control = new PSC({
|
||||
type: '1.2.840.113556.1.4.319',
|
||||
criticality: true,
|
||||
value: {
|
||||
size: 1,
|
||||
cookie: 'foo'
|
||||
}
|
||||
})
|
||||
t.ok(control)
|
||||
t.equal(control.type, '1.2.840.113556.1.4.319')
|
||||
t.ok(control.criticality)
|
||||
t.equal(control.value.size, 1)
|
||||
t.equal(Buffer.from('foo').compare(control.value.cookie), 0)
|
||||
})
|
||||
|
||||
t.test('with value buffer', async t => {
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(1)
|
||||
value.writeBuffer(Buffer.from('foo'), 0x04)
|
||||
value.endSequence()
|
||||
|
||||
const control = new PSC({ value: value.buffer })
|
||||
t.equal(control.value.size, 1)
|
||||
t.equal(Buffer.from('foo').compare(control.value.cookie), 0)
|
||||
})
|
||||
|
||||
t.test('with value buffer (empty cookie)', async t => {
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(1)
|
||||
value.endSequence()
|
||||
|
||||
const control = new PSC({ value: value.buffer })
|
||||
t.equal(control.value.size, 1)
|
||||
t.equal(Buffer.alloc(0).compare(control.value.cookie), 0)
|
||||
})
|
||||
|
||||
t.test('throws for bad value', async t => {
|
||||
t.throws(() => new PSC({ value: 42 }))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('pojo', t => {
|
||||
t.test('adds control value', async t => {
|
||||
const control = new PSC({
|
||||
value: {
|
||||
size: 1,
|
||||
cookie: 'foo'
|
||||
}
|
||||
})
|
||||
t.same(control.pojo, {
|
||||
type: PSC.OID,
|
||||
criticality: false,
|
||||
value: {
|
||||
size: 1,
|
||||
cookie: Buffer.from('foo')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('converts empty instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(PSC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(1)
|
||||
value.writeString('foo')
|
||||
value.endSequence()
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new PSC({
|
||||
value: {
|
||||
size: 1,
|
||||
cookie: 'foo'
|
||||
}
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts empty instance to BER (empty cookie)', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(PSC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(1)
|
||||
value.writeString('')
|
||||
value.endSequence()
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new PSC({
|
||||
value: {
|
||||
size: 1
|
||||
}
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
118
node_modules/@ldapjs/controls/lib/controls/password-policy-control.js
generated
vendored
Normal file
118
node_modules/@ldapjs/controls/lib/controls/password-policy-control.js
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
'use strict'
|
||||
|
||||
const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const Control = require('../control')
|
||||
|
||||
/**
|
||||
* @typedef {object} PasswordPolicyResponseControlValue
|
||||
* @property {number} error One of 0 (passwordExpired), 1 (accountLocked),
|
||||
* 2 (changeAfterReset), 3 (passwordModNotAllowed), 4 (mustSupplyOldPassword),
|
||||
* 5 (insufficientPasswordQuality), 6 (passwordTooShort), 7 (passwordTooYoung),
|
||||
* 8 (passwordInHistory), 9 (passwordTooYoung)
|
||||
* @property {number} timeBeforeExpiration
|
||||
* @property {number} graceAuthNsRemaining
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements both request and response controls:
|
||||
* https://datatracker.ietf.org/doc/html/draft-behera-ldap-password-policy-11#name-controls-used-for-password-
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class PasswordPolicyControl extends Control {
|
||||
static OID = '1.3.6.1.4.1.42.2.27.8.5.1'
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} PasswordPolicyResponseParams
|
||||
* @property {PasswordPolicyResponseControlValue | Buffer} [value]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new password policy control.
|
||||
*
|
||||
* @param {PasswordPolicyResponseParams} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
options.type = PasswordPolicyControl.OID
|
||||
super(options)
|
||||
|
||||
this._value = {}
|
||||
|
||||
if (hasOwn(options, 'value') === false) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(options.value)) {
|
||||
this.#parse(options.value)
|
||||
} else if (isObject(options.value)) {
|
||||
if (hasOwn(options.value, 'timeBeforeExpiration') === true && hasOwn(options.value, 'graceAuthNsRemaining') === true) {
|
||||
throw new Error('options.value must contain either timeBeforeExpiration or graceAuthNsRemaining, not both')
|
||||
}
|
||||
this._value = options.value
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer or Object')
|
||||
}
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (obj) {
|
||||
this._value = Object.assign({}, this._value, obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a BER buffer that represents a
|
||||
* {@link PasswordPolicyResponseControlValue}, read that buffer into the
|
||||
* current instance.
|
||||
*/
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
if (ber.readSequence()) {
|
||||
this._value = {}
|
||||
if (ber.peek() === 0xa0) {
|
||||
ber.readSequence(0xa0)
|
||||
if (ber.peek() === 0x80) {
|
||||
this._value.timeBeforeExpiration = ber._readTag(0x80)
|
||||
} else if (ber.peek() === 0x81) {
|
||||
this._value.graceAuthNsRemaining = ber._readTag(0x81)
|
||||
}
|
||||
}
|
||||
if (ber.peek() === 0x81) {
|
||||
this._value.error = ber._readTag(0x81)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
if (!this._value || Object.keys(this._value).length === 0) { return }
|
||||
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence()
|
||||
if (hasOwn(this._value, 'timeBeforeExpiration')) {
|
||||
writer.startSequence(0xa0)
|
||||
writer.writeInt(this._value.timeBeforeExpiration, 0x80)
|
||||
writer.endSequence()
|
||||
} else if (hasOwn(this._value, 'graceAuthNsRemaining')) {
|
||||
writer.startSequence(0xa0)
|
||||
writer.writeInt(this._value.graceAuthNsRemaining, 0x81)
|
||||
writer.endSequence()
|
||||
}
|
||||
if (hasOwn(this._value, 'error')) {
|
||||
writer.writeInt(this._value.error, 0x81)
|
||||
}
|
||||
writer.endSequence()
|
||||
|
||||
ber.writeBuffer(writer.buffer, 0x04)
|
||||
return ber
|
||||
}
|
||||
|
||||
_updatePlainObject (obj) {
|
||||
obj.controlValue = this.value
|
||||
return obj
|
||||
}
|
||||
}
|
||||
module.exports = PasswordPolicyControl
|
||||
113
node_modules/@ldapjs/controls/lib/controls/password-policy-control.test.js
generated
vendored
Normal file
113
node_modules/@ldapjs/controls/lib/controls/password-policy-control.test.js
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
const PPC = require('./password-policy-control')
|
||||
const Control = require('../control')
|
||||
|
||||
tap.test('contructor', t => {
|
||||
t.test('new no args', async t => {
|
||||
const control = new PPC()
|
||||
t.ok(control)
|
||||
t.type(control, PPC)
|
||||
t.type(control, Control)
|
||||
t.equal(control.type, PPC.OID)
|
||||
t.same(control.value, {})
|
||||
})
|
||||
|
||||
t.test('new with args', async t => {
|
||||
const control = new PPC({
|
||||
type: '1.3.6.1.4.1.42.2.27.8.5.1',
|
||||
criticality: true,
|
||||
value: {
|
||||
error: 1,
|
||||
timeBeforeExpiration: 2
|
||||
}
|
||||
})
|
||||
t.ok(control)
|
||||
t.equal(control.type, '1.3.6.1.4.1.42.2.27.8.5.1')
|
||||
t.ok(control.criticality)
|
||||
t.same(control.value, {
|
||||
error: 1,
|
||||
timeBeforeExpiration: 2
|
||||
})
|
||||
})
|
||||
|
||||
t.test('with value buffer', async t => {
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(5, 0x81)
|
||||
value.endSequence()
|
||||
|
||||
const control = new PPC({ value: value.buffer })
|
||||
t.same(control.value, {
|
||||
error: 5
|
||||
})
|
||||
})
|
||||
|
||||
t.test('throws for bad value', async t => {
|
||||
t.throws(() => new PPC({ value: 42 }))
|
||||
t.throws(() => new PPC({ value: { timeBeforeExpiration: 1, graceAuthNsRemaining: 2 } }))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('pojo', t => {
|
||||
t.test('adds control value', async t => {
|
||||
const control = new PPC()
|
||||
t.same(control.pojo, {
|
||||
type: PPC.OID,
|
||||
criticality: false,
|
||||
value: {}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('converts empty instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(PPC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
target.endSequence()
|
||||
|
||||
const control = new PPC()
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts full instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(PPC.OID)
|
||||
target.writeBoolean(true) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.startSequence(0xa0)
|
||||
value.writeInt(2, 0x81)
|
||||
value.endSequence()
|
||||
value.writeInt(1, 0x81)
|
||||
value.endSequence()
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new PPC({
|
||||
criticality: true,
|
||||
value: {
|
||||
error: 1,
|
||||
graceAuthNsRemaining: 2
|
||||
}
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
100
node_modules/@ldapjs/controls/lib/controls/persistent-search-control.js
generated
vendored
Normal file
100
node_modules/@ldapjs/controls/lib/controls/persistent-search-control.js
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
'use strict'
|
||||
|
||||
const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const Control = require('../control')
|
||||
|
||||
/**
|
||||
* @typedef {object} PersistentSearchControlValue
|
||||
* @property {number} changeTypes A bitwise OR of 1 (add), 2 (delete),
|
||||
* 4 (modify), and 8 (modifyDN).
|
||||
* @property {boolean} changesOnly
|
||||
* @property {boolean} returnECs
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* https://datatracker.ietf.org/doc/html/draft-ietf-ldapext-psearch-03.txt
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class PersistentSearchControl extends Control {
|
||||
static OID = '2.16.840.1.113730.3.4.3'
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} PersistentSearchParams
|
||||
* @property {PersistentSearchControlValue | Buffer} [value]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new persistent search control.
|
||||
*
|
||||
* @param {PersistentSearchParams} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
options.type = PersistentSearchControl.OID
|
||||
super(options)
|
||||
|
||||
this._value = {
|
||||
changeTypes: 15,
|
||||
changesOnly: true,
|
||||
returnECs: true
|
||||
}
|
||||
|
||||
if (hasOwn(options, 'value') === false) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(options.value)) {
|
||||
this.#parse(options.value)
|
||||
} else if (isObject(options.value)) {
|
||||
this._value = options.value
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer or Object')
|
||||
}
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (obj) {
|
||||
this._value = Object.assign({}, this._value, obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a BER buffer that represents a {@link PersistentSearchControlValue},
|
||||
* read that buffer into the current instance.
|
||||
*/
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (ber.readSequence()) {
|
||||
this._value = {
|
||||
changeTypes: ber.readInt(),
|
||||
changesOnly: ber.readBoolean(),
|
||||
returnECs: ber.readBoolean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence()
|
||||
writer.writeInt(this._value.changeTypes)
|
||||
writer.writeBoolean(this._value.changesOnly)
|
||||
writer.writeBoolean(this._value.returnECs)
|
||||
writer.endSequence()
|
||||
|
||||
ber.writeBuffer(writer.buffer, 0x04)
|
||||
return ber
|
||||
}
|
||||
|
||||
_updatePlainObject (obj) {
|
||||
obj.controlValue = this.value
|
||||
return obj
|
||||
}
|
||||
}
|
||||
module.exports = PersistentSearchControl
|
||||
106
node_modules/@ldapjs/controls/lib/controls/persistent-search-control.test.js
generated
vendored
Normal file
106
node_modules/@ldapjs/controls/lib/controls/persistent-search-control.test.js
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
const PSC = require('./persistent-search-control')
|
||||
const Control = require('../control')
|
||||
|
||||
tap.test('contructor', t => {
|
||||
t.test('new no args', async t => {
|
||||
const control = new PSC()
|
||||
t.ok(control)
|
||||
t.type(control, PSC)
|
||||
t.type(control, Control)
|
||||
t.equal(control.type, PSC.OID)
|
||||
t.same(control.value, {
|
||||
changeTypes: 15,
|
||||
changesOnly: true,
|
||||
returnECs: true
|
||||
})
|
||||
})
|
||||
|
||||
t.test('new with args', async t => {
|
||||
const control = new PSC({
|
||||
type: '2.16.840.1.113730.3.4.3',
|
||||
criticality: true,
|
||||
value: {
|
||||
changeTypes: 1,
|
||||
changesOnly: false,
|
||||
returnECs: true
|
||||
}
|
||||
})
|
||||
t.ok(control)
|
||||
t.equal(control.type, '2.16.840.1.113730.3.4.3')
|
||||
t.ok(control.criticality)
|
||||
t.same(control.value, {
|
||||
changeTypes: 1,
|
||||
changesOnly: false,
|
||||
returnECs: true
|
||||
})
|
||||
})
|
||||
|
||||
t.test('with value buffer', async t => {
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(2)
|
||||
value.writeBoolean(true)
|
||||
value.writeBoolean(false)
|
||||
value.endSequence()
|
||||
|
||||
const control = new PSC({ value: value.buffer })
|
||||
t.same(control.value, {
|
||||
changeTypes: 2,
|
||||
changesOnly: true,
|
||||
returnECs: false
|
||||
})
|
||||
})
|
||||
|
||||
t.test('throws for bad value', async t => {
|
||||
t.throws(() => new PSC({ value: 42 }))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('pojo', t => {
|
||||
t.test('adds control value', async t => {
|
||||
const control = new PSC()
|
||||
t.same(control.pojo, {
|
||||
type: PSC.OID,
|
||||
criticality: false,
|
||||
value: {
|
||||
changeTypes: 15,
|
||||
changesOnly: true,
|
||||
returnECs: true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('converts empty instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(PSC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence()
|
||||
value.writeInt(15)
|
||||
value.writeBoolean(true)
|
||||
value.writeBoolean(true)
|
||||
value.endSequence()
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new PSC()
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
132
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-request-control.js
generated
vendored
Normal file
132
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-request-control.js
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
'use strict'
|
||||
|
||||
const { Ber, BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const Control = require('../control')
|
||||
|
||||
/**
|
||||
* @typedef {object} SortKeyItem
|
||||
* @property {string} attributeType
|
||||
* @property {string} orderingRule
|
||||
* @property {boolean} reverseOrder
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {SortKeyItem[]} ServerSideSortingRequestControlValue
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* https://datatracker.ietf.org/doc/html/draft-ietf-ldapext-sorting#section-3.1
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class ServerSideSortingRequestControl extends Control {
|
||||
static OID = '1.2.840.113556.1.4.473'
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} ServerSideSortingRequestParams
|
||||
* @property {ServerSideSortingRequestControlValue | SortKeyItem | Buffer} [value]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new server side sorting request control.
|
||||
*
|
||||
* @param {ServerSideSortingRequestParams} [options]
|
||||
*/
|
||||
constructor (options = { value: [] }) {
|
||||
options.type = ServerSideSortingRequestControl.OID
|
||||
super(options)
|
||||
|
||||
const inputValue = options.value ?? []
|
||||
if (Buffer.isBuffer(inputValue)) {
|
||||
this.#parse(inputValue)
|
||||
} else if (Array.isArray(inputValue)) {
|
||||
for (const obj of inputValue) {
|
||||
if (isObject(obj) === false) {
|
||||
throw new Error('Control value must be an object')
|
||||
}
|
||||
if (hasOwn(obj, 'attributeType') === false) {
|
||||
throw new Error('Missing required key: attributeType')
|
||||
}
|
||||
}
|
||||
this.value = inputValue
|
||||
} else if (isObject(inputValue)) {
|
||||
if (hasOwn(inputValue, 'attributeType') === false) {
|
||||
throw new Error('Missing required key: attributeType')
|
||||
}
|
||||
this.value = [inputValue]
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer, Array or Object')
|
||||
}
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (items) {
|
||||
if (Buffer.isBuffer(items) === true) return
|
||||
if (Array.isArray(items) === false) {
|
||||
this._value = [items]
|
||||
return
|
||||
}
|
||||
this._value = items
|
||||
}
|
||||
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
let item
|
||||
/* istanbul ignore else */
|
||||
if (ber.readSequence(0x30)) {
|
||||
this.value = []
|
||||
|
||||
while (ber.readSequence(0x30)) {
|
||||
item = {}
|
||||
item.attributeType = ber.readString(Ber.OctetString)
|
||||
/* istanbul ignore else */
|
||||
if (ber.peek() === 0x80) {
|
||||
item.orderingRule = ber.readString(0x80)
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (ber.peek() === 0x81) {
|
||||
item.reverseOrder = (ber._readTag(0x81) !== 0)
|
||||
}
|
||||
this.value.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_pojo (obj) {
|
||||
obj.value = this.value
|
||||
return obj
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
if (this.value.length === 0) { return }
|
||||
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence(0x30)
|
||||
for (let i = 0; i < this.value.length; i++) {
|
||||
const item = this.value[i]
|
||||
writer.startSequence(0x30)
|
||||
/* istanbul ignore else */
|
||||
if (hasOwn(item, 'attributeType')) {
|
||||
writer.writeString(item.attributeType, Ber.OctetString)
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (hasOwn(item, 'orderingRule')) {
|
||||
writer.writeString(item.orderingRule, 0x80)
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (hasOwn(item, 'reverseOrder')) {
|
||||
writer.writeBoolean(item.reverseOrder, 0x81)
|
||||
}
|
||||
writer.endSequence()
|
||||
}
|
||||
writer.endSequence()
|
||||
ber.writeBuffer(writer.buffer, 0x04)
|
||||
}
|
||||
}
|
||||
module.exports = ServerSideSortingRequestControl
|
||||
144
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-request-control.test.js
generated
vendored
Normal file
144
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-request-control.test.js
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
const SSSRC = require('./server-side-sorting-request-control')
|
||||
const Control = require('../control')
|
||||
|
||||
tap.test('contructor', t => {
|
||||
t.test('new no args', async t => {
|
||||
const control = new SSSRC()
|
||||
t.ok(control)
|
||||
t.type(control, SSSRC)
|
||||
t.type(control, Control)
|
||||
t.equal(control.type, SSSRC.OID)
|
||||
t.same(control.value, [])
|
||||
})
|
||||
|
||||
t.test('new with args', async t => {
|
||||
const control = new SSSRC({
|
||||
type: '1.2.840.113556.1.4.473',
|
||||
criticality: true,
|
||||
value: [{ attributeType: 'foo' }]
|
||||
})
|
||||
t.ok(control)
|
||||
t.equal(control.type, '1.2.840.113556.1.4.473')
|
||||
t.ok(control.criticality)
|
||||
t.same(control.value, [{ attributeType: 'foo' }])
|
||||
})
|
||||
|
||||
t.test('new with object', async t => {
|
||||
const control = new SSSRC({
|
||||
type: '1.2.840.113556.1.4.473',
|
||||
criticality: true,
|
||||
value: { attributeType: 'foo' }
|
||||
})
|
||||
t.ok(control)
|
||||
t.equal(control.type, '1.2.840.113556.1.4.473')
|
||||
t.ok(control.criticality)
|
||||
t.same(control.value, [{ attributeType: 'foo' }])
|
||||
})
|
||||
|
||||
t.test('with value buffer', async t => {
|
||||
const value = new BerWriter()
|
||||
value.startSequence(0x30) // Open "array"
|
||||
value.startSequence(0x30) // Start "item"
|
||||
value.writeString('foo', 0x04)
|
||||
value.writeString('bar', 0x80)
|
||||
value.writeBoolean(false, 0x81)
|
||||
value.endSequence() // End item
|
||||
value.endSequence() // Close array
|
||||
|
||||
const control = new SSSRC({ value: value.buffer })
|
||||
t.same(control.value, [{
|
||||
attributeType: 'foo',
|
||||
orderingRule: 'bar',
|
||||
reverseOrder: false
|
||||
}])
|
||||
})
|
||||
|
||||
t.test('throws for bad value', async t => {
|
||||
t.throws(() => new SSSRC({ value: 42 }))
|
||||
})
|
||||
|
||||
t.test('throws for bad object value', async t => {
|
||||
t.throws(() => new SSSRC({ value: { foo: 'bar' } }))
|
||||
})
|
||||
|
||||
t.test('throws for bad array value', async t => {
|
||||
t.throws(() => new SSSRC({ value: [42] }))
|
||||
t.throws(() => new SSSRC({ value: [{ foo: 'bar' }] }))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('pojo', t => {
|
||||
t.test('adds control value', async t => {
|
||||
const control = new SSSRC()
|
||||
t.same(control.pojo, {
|
||||
type: SSSRC.OID,
|
||||
criticality: false,
|
||||
value: []
|
||||
})
|
||||
})
|
||||
|
||||
t.test('_pojo', async t => {
|
||||
const control = new SSSRC()
|
||||
const obj = control._pojo({ value: 'change_me' })
|
||||
t.strictSame(obj, { value: [] })
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('converts empty instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(SSSRC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
target.endSequence()
|
||||
|
||||
const control = new SSSRC()
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts full instance BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(SSSRC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence(0x30) // Open "array"
|
||||
value.startSequence(0x30) // Start "item"
|
||||
value.writeString('one', 0x04)
|
||||
value.writeString('one', 0x80)
|
||||
value.writeBoolean(false, 0x81)
|
||||
value.endSequence() // End item
|
||||
value.startSequence(0x30) // Start "item"
|
||||
value.writeString('two', 0x04)
|
||||
value.writeString('two', 0x80)
|
||||
value.writeBoolean(true, 0x81)
|
||||
value.endSequence() // End item
|
||||
value.endSequence() // Close array
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new SSSRC({
|
||||
value: [
|
||||
{ attributeType: 'one', orderingRule: 'one', reverseOrder: false },
|
||||
{ attributeType: 'two', orderingRule: 'two', reverseOrder: true }
|
||||
]
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(Buffer.from(target.buffer), ber.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
129
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-response-control.js
generated
vendored
Normal file
129
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-response-control.js
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
'use strict'
|
||||
|
||||
const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const Control = require('../control')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const { resultCodes: RESULT_CODES } = require('@ldapjs/protocol')
|
||||
|
||||
const validCodeNames = [
|
||||
'SUCCESS',
|
||||
'OPERATIONS_ERROR',
|
||||
'TIME_LIMIT_EXCEEDED',
|
||||
'STRONGER_AUTH_REQUIRED',
|
||||
'ADMIN_LIMIT_EXCEEDED',
|
||||
'NO_SUCH_ATTRIBUTE',
|
||||
'INAPPROPRIATE_MATCHING',
|
||||
'INSUFFICIENT_ACCESS_RIGHTS',
|
||||
'BUSY',
|
||||
'UNWILLING_TO_PERFORM',
|
||||
'OTHER'
|
||||
]
|
||||
|
||||
const filteredCodes = Object.entries(RESULT_CODES).filter(([k, v]) => validCodeNames.includes(k))
|
||||
const VALID_CODES = new Map([
|
||||
...filteredCodes,
|
||||
...filteredCodes.map(([k, v]) => { return [v, k] })
|
||||
])
|
||||
|
||||
/**
|
||||
* @typedef {object} ServerSideSortingResponseControlResult
|
||||
* @property {number} result
|
||||
* @property {string} failedAttribute
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* https://datatracker.ietf.org/doc/html/draft-ietf-ldapext-sorting#section-3.2
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class ServerSideSortingResponseControl extends Control {
|
||||
static OID = '1.2.840.113556.1.4.474'
|
||||
|
||||
/**
|
||||
* A map of possible response codes. Includes `CODE => VALUE` and
|
||||
* `VALUE => CODE`. For example, `RESPONSE_CODES.get(0)` returns
|
||||
* `LDAP_SUCCESS`, and `RESPONSE_CODES.get('LDAP_SUCCESS')` returns `0`.
|
||||
*/
|
||||
static RESPONSE_CODES = Object.freeze(VALID_CODES)
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} ServerSideSortingResponseParams
|
||||
* @property {ServerSideSortingResponseControlResult | Buffer} value
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new server side sorting response control.
|
||||
*
|
||||
* @param {ServerSideSortingResponseParams} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
options.type = ServerSideSortingResponseControl.OID
|
||||
options.criticality = false
|
||||
super(options)
|
||||
|
||||
this.value = {}
|
||||
|
||||
if (hasOwn(options, 'value') === false || !options.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const value = options.value
|
||||
if (Buffer.isBuffer(value)) {
|
||||
this.#parse(value)
|
||||
} else if (isObject(value)) {
|
||||
if (VALID_CODES.has(value.result) === false) {
|
||||
throw new Error('Invalid result code')
|
||||
}
|
||||
if (hasOwn(value, 'failedAttribute') && (typeof value.failedAttribute) !== 'string') {
|
||||
throw new Error('failedAttribute must be String')
|
||||
}
|
||||
|
||||
this.value = value
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer or Object')
|
||||
}
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (obj) {
|
||||
this._value = Object.assign({}, this._value, obj)
|
||||
}
|
||||
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
/* istanbul ignore else */
|
||||
if (ber.readSequence(0x30)) {
|
||||
this._value = {}
|
||||
this._value.result = ber.readEnumeration()
|
||||
/* istanbul ignore else */
|
||||
if (ber.peek() === 0x80) {
|
||||
this._value.failedAttribute = ber.readString(0x80)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_pojo (obj) {
|
||||
obj.value = this.value
|
||||
return obj
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
if (!this._value || Object.keys(this._value).length === 0) { return }
|
||||
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence(0x30)
|
||||
writer.writeEnumeration(this.value.result)
|
||||
/* istanbul ignore else */
|
||||
if (this.value.result !== RESULT_CODES.SUCCESS && this.value.failedAttribute) {
|
||||
writer.writeString(this.value.failedAttribute, 0x80)
|
||||
}
|
||||
writer.endSequence()
|
||||
ber.writeBuffer(writer.buffer, 0x04)
|
||||
}
|
||||
}
|
||||
module.exports = ServerSideSortingResponseControl
|
||||
125
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-response-control.test.js
generated
vendored
Normal file
125
node_modules/@ldapjs/controls/lib/controls/server-side-sorting-response-control.test.js
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerWriter } = require('@ldapjs/asn1')
|
||||
const SSSRC = require('./server-side-sorting-response-control')
|
||||
const Control = require('../control')
|
||||
|
||||
tap.test('constructor', t => {
|
||||
t.test('new no args', async t => {
|
||||
const control = new SSSRC()
|
||||
t.ok(control)
|
||||
t.type(control, SSSRC)
|
||||
t.type(control, Control)
|
||||
t.equal(control.type, SSSRC.OID)
|
||||
t.same(control.value, {})
|
||||
})
|
||||
|
||||
t.test('new with args', async t => {
|
||||
const control = new SSSRC({
|
||||
type: '1.2.840.113556.1.4.474',
|
||||
criticality: true,
|
||||
value: {
|
||||
result: SSSRC.RESPONSE_CODES.get('OPERATIONS_ERROR'),
|
||||
failedAttribute: 'foo'
|
||||
}
|
||||
})
|
||||
t.ok(control)
|
||||
t.equal(control.type, '1.2.840.113556.1.4.474')
|
||||
t.equal(control.criticality, false)
|
||||
t.same(control.value, {
|
||||
result: 1,
|
||||
failedAttribute: 'foo'
|
||||
})
|
||||
})
|
||||
|
||||
t.test('with value buffer', async t => {
|
||||
const value = new BerWriter()
|
||||
value.startSequence(0x30)
|
||||
value.writeEnumeration(1)
|
||||
value.writeString('foo', 0x80)
|
||||
value.endSequence()
|
||||
|
||||
const control = new SSSRC({ value: value.buffer })
|
||||
t.same(control.value, {
|
||||
result: 1,
|
||||
failedAttribute: 'foo'
|
||||
})
|
||||
})
|
||||
|
||||
t.test('throws for bad value', async t => {
|
||||
t.throws(() => new SSSRC({ value: 42 }))
|
||||
t.throws(() => new SSSRC({ value: {} }))
|
||||
t.throws(() => new SSSRC({
|
||||
value: {
|
||||
result: 1,
|
||||
failedAttribute: 42
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('pojo', t => {
|
||||
t.test('adds control value', async t => {
|
||||
const control = new SSSRC()
|
||||
t.same(control.pojo, {
|
||||
type: SSSRC.OID,
|
||||
criticality: false,
|
||||
value: {}
|
||||
})
|
||||
})
|
||||
|
||||
t.test('_pojo', async t => {
|
||||
const control = new SSSRC()
|
||||
t.strictSame(control._pojo({ value: 'change_me' }), {
|
||||
value: {}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('converts empty instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(SSSRC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
target.endSequence()
|
||||
|
||||
const control = new SSSRC()
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.test('converts full instance to BER', async t => {
|
||||
const target = new BerWriter()
|
||||
target.startSequence()
|
||||
target.writeString(SSSRC.OID)
|
||||
target.writeBoolean(false) // Control.criticality
|
||||
|
||||
const value = new BerWriter()
|
||||
value.startSequence(0x30)
|
||||
value.writeEnumeration(1)
|
||||
value.writeString('foo', 0x80)
|
||||
value.endSequence()
|
||||
|
||||
target.writeBuffer(value.buffer, 0x04)
|
||||
target.endSequence()
|
||||
|
||||
const control = new SSSRC({
|
||||
value: {
|
||||
result: SSSRC.RESPONSE_CODES.get('OPERATIONS_ERROR'),
|
||||
failedAttribute: 'foo'
|
||||
}
|
||||
})
|
||||
const ber = control.toBer()
|
||||
|
||||
t.equal(Buffer.compare(ber.buffer, target.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
116
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-request-control.js
generated
vendored
Normal file
116
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-request-control.js
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
'use strict'
|
||||
|
||||
const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const Control = require('../control')
|
||||
|
||||
/**
|
||||
* @typedef {object} VirtualListViewControlValue
|
||||
* @property {number} beforeCount
|
||||
* @property {number} afterCount
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* https://datatracker.ietf.org/doc/html/draft-ietf-ldapext-ldapv3-vlv-07#section-6.1
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class VirtualListViewRequestControl extends Control {
|
||||
static OID = '2.16.840.1.113730.3.4.9'
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} VirtualListViewRequestParams
|
||||
* @property {Buffer|VirtualListViewControlValue} [value]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {VirtualListViewRequestParams} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
options.type = VirtualListViewRequestControl.OID
|
||||
super(options)
|
||||
|
||||
if (hasOwn(options, 'value') === false) {
|
||||
// return
|
||||
throw Error('control is not enabled')
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(options.value)) {
|
||||
this.#parse(options.value)
|
||||
} else if (isObject(options.value)) {
|
||||
if (Object.prototype.hasOwnProperty.call(options.value, 'beforeCount') === false) {
|
||||
throw new Error('Missing required key: beforeCount')
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(options.value, 'afterCount') === false) {
|
||||
throw new Error('Missing required key: afterCount')
|
||||
}
|
||||
this._value = options.value
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer or Object')
|
||||
}
|
||||
|
||||
throw Error('control is not enabled')
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (items) {
|
||||
if (Buffer.isBuffer(items) === true) return
|
||||
if (Array.isArray(items) === false) {
|
||||
this._value = [items]
|
||||
return
|
||||
}
|
||||
this._value = items
|
||||
}
|
||||
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
if (ber.readSequence()) {
|
||||
this._value = {}
|
||||
this._value.beforeCount = ber.readInt()
|
||||
this._value.afterCount = ber.readInt()
|
||||
if (ber.peek() === 0xa0) {
|
||||
if (ber.readSequence(0xa0)) {
|
||||
this._value.targetOffset = ber.readInt()
|
||||
this._value.contentCount = ber.readInt()
|
||||
}
|
||||
}
|
||||
if (ber.peek() === 0x81) {
|
||||
this._value.greaterThanOrEqual = ber.readString(0x81)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
_pojo (obj) {
|
||||
obj.value = this.value
|
||||
return obj
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
if (!this._value || this._value.length === 0) {
|
||||
return
|
||||
}
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence(0x30)
|
||||
writer.writeInt(this._value.beforeCount)
|
||||
writer.writeInt(this._value.afterCount)
|
||||
if (this._value.targetOffset !== undefined) {
|
||||
writer.startSequence(0xa0)
|
||||
writer.writeInt(this._value.targetOffset)
|
||||
writer.writeInt(this._value.contentCount)
|
||||
writer.endSequence()
|
||||
} else if (this._value.greaterThanOrEqual !== undefined) {
|
||||
writer.writeString(this._value.greaterThanOrEqual, 0x81)
|
||||
}
|
||||
writer.endSequence()
|
||||
ber.writeBuffer(writer.buffer, 0x04)
|
||||
}
|
||||
}
|
||||
module.exports = VirtualListViewRequestControl
|
||||
110
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-request-control.test.js
generated
vendored
Normal file
110
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-request-control.test.js
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
tap.test('stubbed', async t => {
|
||||
t.pass()
|
||||
})
|
||||
|
||||
/**
|
||||
* This test is disabled. The commented code below is directly copied from
|
||||
* the original test file in the core `node-ldapjs` repo. The actual test
|
||||
* suite should follow the patterns of the
|
||||
* server-side-sorting-request-control.test.js test suite.
|
||||
*
|
||||
* See https://github.com/ldapjs/node-ldapjs/pull/797#issuecomment-1094132289
|
||||
*/
|
||||
|
||||
// 'use strict'
|
||||
|
||||
// const { test } = require('tap')
|
||||
// const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
// const { getControl, VirtualListViewRequestControl: VLVRControl } = require('../../lib')
|
||||
|
||||
// test('VLV request - new no args', function (t) {
|
||||
// t.ok(new VLVRControl())
|
||||
// t.end()
|
||||
// })
|
||||
|
||||
// test('VLV request - new with args', function (t) {
|
||||
// const c = new VLVRControl({
|
||||
// criticality: true,
|
||||
// value: {
|
||||
// beforeCount: 0,
|
||||
// afterCount: 3,
|
||||
// targetOffset: 1,
|
||||
// contentCount: 0
|
||||
// }
|
||||
// })
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, '2.16.840.1.113730.3.4.9')
|
||||
// t.ok(c.criticality)
|
||||
// t.equal(c.value.beforeCount, 0)
|
||||
// t.equal(c.value.afterCount, 3)
|
||||
// t.equal(c.value.targetOffset, 1)
|
||||
// t.equal(c.value.contentCount, 0)
|
||||
|
||||
// t.end()
|
||||
// })
|
||||
|
||||
// test('VLV request - toBer - with offset', function (t) {
|
||||
// const vlvc = new VLVRControl({
|
||||
// criticality: true,
|
||||
// value: {
|
||||
// beforeCount: 0,
|
||||
// afterCount: 3,
|
||||
// targetOffset: 1,
|
||||
// contentCount: 0
|
||||
// }
|
||||
// })
|
||||
|
||||
// const ber = new BerWriter()
|
||||
// vlvc.toBer(ber)
|
||||
|
||||
// const c = getControl(new BerReader(ber.buffer))
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, '2.16.840.1.113730.3.4.9')
|
||||
// t.ok(c.criticality)
|
||||
// t.equal(c.value.beforeCount, 0)
|
||||
// t.equal(c.value.afterCount, 3)
|
||||
// t.equal(c.value.targetOffset, 1)
|
||||
// t.equal(c.value.contentCount, 0)
|
||||
|
||||
// t.end()
|
||||
// })
|
||||
|
||||
// test('VLV request - toBer - with assertion', function (t) {
|
||||
// const vlvc = new VLVRControl({
|
||||
// criticality: true,
|
||||
// value: {
|
||||
// beforeCount: 0,
|
||||
// afterCount: 3,
|
||||
// greaterThanOrEqual: '*foo*'
|
||||
// }
|
||||
// })
|
||||
|
||||
// const ber = new BerWriter()
|
||||
// vlvc.toBer(ber)
|
||||
|
||||
// const c = getControl(new BerReader(ber.buffer))
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, '2.16.840.1.113730.3.4.9')
|
||||
// t.ok(c.criticality)
|
||||
// t.equal(c.value.beforeCount, 0)
|
||||
// t.equal(c.value.afterCount, 3)
|
||||
// t.equal(c.value.greaterThanOrEqual, '*foo*')
|
||||
|
||||
// t.end()
|
||||
// })
|
||||
|
||||
// test('VLV request - toBer - empty', function (t) {
|
||||
// const vlvc = new VLVRControl()
|
||||
// const ber = new BerWriter()
|
||||
// vlvc.toBer(ber)
|
||||
|
||||
// const c = getControl(new BerReader(ber.buffer))
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, '2.16.840.1.113730.3.4.9')
|
||||
// t.equal(c.criticality, false)
|
||||
// t.notOk(c.value.result)
|
||||
// t.end()
|
||||
// })
|
||||
150
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-response-control.js
generated
vendored
Normal file
150
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-response-control.js
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
'use strict'
|
||||
|
||||
const { Ber, BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const isObject = require('../is-object')
|
||||
const hasOwn = require('../has-own')
|
||||
const Control = require('../control')
|
||||
const { resultCodes: RESULT_CODES } = require('@ldapjs/protocol')
|
||||
|
||||
const validCodeNames = [
|
||||
'SUCCESS',
|
||||
'OPERATIONS_ERROR',
|
||||
'UNWILLING_TO_PERFORM',
|
||||
'INSUFFICIENT_ACCESS_RIGHTS',
|
||||
'BUSY',
|
||||
'TIME_LIMIT_EXCEEDED',
|
||||
'STRONGER_AUTH_REQUIRED',
|
||||
'ADMIN_LIMIT_EXCEEDED',
|
||||
'SORT_CONTROL_MISSING',
|
||||
'OFFSET_RANGE_ERROR',
|
||||
'CONTROL_ERROR',
|
||||
'OTHER'
|
||||
]
|
||||
|
||||
const filteredCodes = Object.entries(RESULT_CODES).filter(([k, v]) => validCodeNames.includes(k))
|
||||
const VALID_CODES = new Map([
|
||||
...filteredCodes,
|
||||
...filteredCodes.map(([k, v]) => { return [v, k] })
|
||||
])
|
||||
|
||||
// TODO: complete this doc block based on the "implements" spec link
|
||||
/**
|
||||
* @typedef {object} VirtualListViewResponseControlValue
|
||||
* @property {number} result A valid LDAP response code for the control.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* https://datatracker.ietf.org/doc/html/draft-ietf-ldapext-ldapv3-vlv-07#section-6.2
|
||||
*
|
||||
* @extends Control
|
||||
*/
|
||||
class VirtualListViewResponseControl extends Control {
|
||||
static OID = '2.16.840.1.113730.3.4.10'
|
||||
|
||||
/**
|
||||
* A map of possible response codes. Includes `CODE => VALUE` and
|
||||
* `VALUE => CODE`. For example, `RESPONSE_CODES.get(0)` returns
|
||||
* `LDAP_SUCCESS`, and `RESPONSE_CODES.get('LDAP_SUCCESS')` returns `0`.
|
||||
*/
|
||||
static RESPONSE_CODES = Object.freeze(VALID_CODES)
|
||||
|
||||
/**
|
||||
* @typedef {ControlParams} VirtualListViewResponseParams
|
||||
* @property {Buffer|VirtualListViewResponseControlValue} [value]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {VirtualListViewResponseParams} options
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
options.type = VirtualListViewResponseControl.OID
|
||||
options.criticality = false
|
||||
super(options)
|
||||
|
||||
this.value = {}
|
||||
|
||||
if (hasOwn(options, 'value') === false || !options.value) {
|
||||
// return
|
||||
throw Error('control not enabled')
|
||||
}
|
||||
|
||||
const value = options.value
|
||||
if (Buffer.isBuffer(value)) {
|
||||
this.#parse(options.value)
|
||||
} else if (isObject(value)) {
|
||||
if (VALID_CODES.has(value.result) === false) {
|
||||
throw new Error('Invalid result code')
|
||||
}
|
||||
this.value = options.value
|
||||
} else {
|
||||
throw new TypeError('options.value must be a Buffer or Object')
|
||||
}
|
||||
|
||||
throw Error('control not enabled')
|
||||
}
|
||||
|
||||
get value () {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value (obj) {
|
||||
this._value = Object.assign({}, this._value, obj)
|
||||
}
|
||||
|
||||
#parse (buffer) {
|
||||
const ber = new BerReader(buffer)
|
||||
if (ber.readSequence()) {
|
||||
this._value = {}
|
||||
|
||||
if (ber.peek(0x02)) {
|
||||
this._value.targetPosition = ber.readInt()
|
||||
}
|
||||
|
||||
if (ber.peek(0x02)) {
|
||||
this._value.contentCount = ber.readInt()
|
||||
}
|
||||
|
||||
this._value.result = ber.readEnumeration()
|
||||
this._value.cookie = ber.readString(Ber.OctetString, true)
|
||||
|
||||
// readString returns '' instead of a zero-length buffer
|
||||
if (!this._value.cookie) {
|
||||
this._value.cookie = Buffer.alloc(0)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
_pojo (obj) {
|
||||
obj.value = this.value
|
||||
return obj
|
||||
}
|
||||
|
||||
_toBer (ber) {
|
||||
if (this.value.length === 0) { return }
|
||||
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence()
|
||||
if (this.value.targetPosition !== undefined) {
|
||||
writer.writeInt(this.value.targetPosition)
|
||||
}
|
||||
if (this.value.contentCount !== undefined) {
|
||||
writer.writeInt(this.value.contentCount)
|
||||
}
|
||||
|
||||
writer.writeEnumeration(this.value.result)
|
||||
if (this.value.cookie && this.value.cookie.length > 0) {
|
||||
writer.writeBuffer(this.value.cookie, Ber.OctetString)
|
||||
} else {
|
||||
writer.writeString('') // writeBuffer rejects zero-length buffers
|
||||
}
|
||||
|
||||
writer.endSequence()
|
||||
ber.writeBuffer(writer.buffer, 0x04)
|
||||
}
|
||||
}
|
||||
module.exports = VirtualListViewResponseControl
|
||||
84
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-response-control.test.js
generated
vendored
Normal file
84
node_modules/@ldapjs/controls/lib/controls/virtual-list-view-response-control.test.js
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
tap.test('stubbed', async t => {
|
||||
t.pass()
|
||||
})
|
||||
|
||||
/**
|
||||
* This test is disabled. The commented code below is directly copied from
|
||||
* the original test file in the core `node-ldapjs` repo. The actual test
|
||||
* suite should follow the patterns of the
|
||||
* server-side-sorting-response-control.test.js test suite.
|
||||
*
|
||||
* See https://github.com/ldapjs/node-ldapjs/pull/797#issuecomment-1094132289
|
||||
*/
|
||||
|
||||
// 'use strict'
|
||||
|
||||
// const { test } = require('tap')
|
||||
// const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
// const ldap = require('../../lib')
|
||||
// const { getControl, VirtualListViewResponseControl: VLVResponseControl } = require('../../lib')
|
||||
// const OID = '2.16.840.1.113730.3.4.10'
|
||||
|
||||
// test('VLV response - new no args', function (t) {
|
||||
// const c = new VLVResponseControl()
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, OID)
|
||||
// t.equal(c.criticality, false)
|
||||
// t.end()
|
||||
// })
|
||||
|
||||
// test('VLV response - new with args', function (t) {
|
||||
// const c = new VLVResponseControl({
|
||||
// criticality: true,
|
||||
// value: {
|
||||
// result: ldap.LDAP_SUCCESS,
|
||||
// targetPosition: 0,
|
||||
// contentCount: 10
|
||||
// }
|
||||
// })
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, OID)
|
||||
// t.equal(c.criticality, false)
|
||||
// t.equal(c.value.result, ldap.LDAP_SUCCESS)
|
||||
// t.equal(c.value.targetPosition, 0)
|
||||
// t.equal(c.value.contentCount, 10)
|
||||
// t.end()
|
||||
// })
|
||||
|
||||
// test('VLV response - toBer', function (t) {
|
||||
// const vlpc = new VLVResponseControl({
|
||||
// value: {
|
||||
// targetPosition: 0,
|
||||
// contentCount: 10,
|
||||
// result: ldap.LDAP_SUCCESS
|
||||
// }
|
||||
// })
|
||||
|
||||
// const ber = new BerWriter()
|
||||
// vlpc.toBer(ber)
|
||||
|
||||
// const c = getControl(new BerReader(ber.buffer))
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, OID)
|
||||
// t.equal(c.criticality, false)
|
||||
// t.equal(c.value.result, ldap.LDAP_SUCCESS)
|
||||
// t.equal(c.value.targetPosition, 0)
|
||||
// t.equal(c.value.contentCount, 10)
|
||||
// t.end()
|
||||
// })
|
||||
|
||||
// test('VLV response - toBer - empty', function (t) {
|
||||
// const vlpc = new VLVResponseControl()
|
||||
// const ber = new BerWriter()
|
||||
// vlpc.toBer(ber)
|
||||
|
||||
// const c = getControl(new BerReader(ber.buffer))
|
||||
// t.ok(c)
|
||||
// t.equal(c.type, OID)
|
||||
// t.equal(c.criticality, false)
|
||||
// t.notOk(c.value.result)
|
||||
// t.end()
|
||||
// })
|
||||
5
node_modules/@ldapjs/controls/lib/has-own.js
generated
vendored
Normal file
5
node_modules/@ldapjs/controls/lib/has-own.js
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function hasOwn (obj, prop) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, prop)
|
||||
}
|
||||
5
node_modules/@ldapjs/controls/lib/is-object.js
generated
vendored
Normal file
5
node_modules/@ldapjs/controls/lib/is-object.js
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function isObject (input) {
|
||||
return Object.prototype.toString.call(input) === '[object Object]'
|
||||
}
|
||||
Reference in New Issue
Block a user