First commit
This commit is contained in:
9
node_modules/@ldapjs/change/.eslintrc
generated
vendored
Normal file
9
node_modules/@ldapjs/change/.eslintrc
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest"
|
||||
},
|
||||
|
||||
"extends": [
|
||||
"standard"
|
||||
]
|
||||
}
|
||||
10
node_modules/@ldapjs/change/.github/workflows/main.yml
generated
vendored
Normal file
10
node_modules/@ldapjs/change/.github/workflows/main.yml
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
name: "CI"
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
call-core-ci:
|
||||
uses: ldapjs/.github/.github/workflows/node-ci.yml@main
|
||||
6
node_modules/@ldapjs/change/.taprc.yaml
generated
vendored
Normal file
6
node_modules/@ldapjs/change/.taprc.yaml
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
reporter: terse
|
||||
coverage-map: coverage-map.js
|
||||
|
||||
files:
|
||||
- 'index.test.js'
|
||||
# - 'lib/**/*.test.js'
|
||||
21
node_modules/@ldapjs/change/LICENSE
generated
vendored
Normal file
21
node_modules/@ldapjs/change/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
Copyright (c) 2014 Patrick Mooney. All rights reserved.
|
||||
Copyright (c) 2014 Mark Cavage, Inc. All rights reserved.
|
||||
Copyright (c) 2022 The LDAPJS Collaborators.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE
|
||||
8
node_modules/@ldapjs/change/README.md
generated
vendored
Normal file
8
node_modules/@ldapjs/change/README.md
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# change
|
||||
|
||||
Provides objects for managing changes as described in
|
||||
[RFC 4511 §4.6](https://www.rfc-editor.org/rfc/rfc4511.html#section-4.6).
|
||||
|
||||
## License
|
||||
|
||||
MIT.
|
||||
3
node_modules/@ldapjs/change/coverage-map.js
generated
vendored
Normal file
3
node_modules/@ldapjs/change/coverage-map.js
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = testFile => testFile.replace(/\.test\.js$/, '.js')
|
||||
320
node_modules/@ldapjs/change/index.js
generated
vendored
Normal file
320
node_modules/@ldapjs/change/index.js
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
'use strict'
|
||||
|
||||
const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const Attribute = require('@ldapjs/attribute')
|
||||
|
||||
/**
|
||||
* Implements an LDAP CHANGE sequence as described in
|
||||
* https://www.rfc-editor.org/rfc/rfc4511.html#section-4.6.
|
||||
*/
|
||||
class Change {
|
||||
#operation
|
||||
#modification
|
||||
|
||||
/**
|
||||
* @typedef {object} ChangeParameters
|
||||
* @property {string | number} operation One of `add` (0), `delete` (1), or
|
||||
* `replace` (2). Default: `add`.
|
||||
* @property {object | import('@ldapjs/attribute')} modification An attribute
|
||||
* instance or an object that is shaped like an attribute.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {ChangeParameters} input
|
||||
*
|
||||
* @throws When the `modification` parameter is invalid.
|
||||
*/
|
||||
constructor ({ operation = 'add', modification }) {
|
||||
this.operation = operation
|
||||
this.modification = modification
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag] () {
|
||||
return 'LdapChange'
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute that will be modified by the {@link Change}.
|
||||
*
|
||||
* @returns {import('@ldapjs/attribute')}
|
||||
*/
|
||||
get modification () {
|
||||
return this.#modification
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the attribute to be modified by the {@link Change}.
|
||||
*
|
||||
* @param {object|import('@ldapjs/attribute')} mod
|
||||
*
|
||||
* @throws When `mod` is not an instance of `Attribute` or is not an
|
||||
* `Attribute` shaped object.
|
||||
*/
|
||||
set modification (mod) {
|
||||
if (Attribute.isAttribute(mod) === false) {
|
||||
throw Error('modification must be an Attribute')
|
||||
}
|
||||
if (Object.prototype.toString.call(mod) !== '[object LdapAttribute]') {
|
||||
mod = new Attribute(mod)
|
||||
}
|
||||
this.#modification = mod
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a plain JavaScript object representation of the change.
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
get pojo () {
|
||||
return {
|
||||
operation: this.operation,
|
||||
modification: this.modification.pojo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The string name of the operation that will be performed.
|
||||
*
|
||||
* @returns {string} One of `add`, `delete`, or `replace`.
|
||||
*/
|
||||
get operation () {
|
||||
switch (this.#operation) {
|
||||
case 0x00: {
|
||||
return 'add'
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
return 'delete'
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
return 'replace'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the operation that the {@link Change} represents.
|
||||
*
|
||||
* @param {string|number} op May be one of `add` (0), `delete` (1),
|
||||
* or `replace` (2).
|
||||
*
|
||||
* @throws When the `op` is not recognized.
|
||||
*/
|
||||
set operation (op) {
|
||||
if (typeof op === 'string') {
|
||||
op = op.toLowerCase()
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case 0x00:
|
||||
case 'add': {
|
||||
this.#operation = 0x00
|
||||
break
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
case 'delete': {
|
||||
this.#operation = 0x01
|
||||
break
|
||||
}
|
||||
|
||||
case 0x02:
|
||||
case 'replace': {
|
||||
this.#operation = 0x02
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
const type = Number.isInteger(op)
|
||||
? '0x' + Number(op).toString(16)
|
||||
: op
|
||||
throw Error(`invalid operation type: ${type}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the instance to a BER.
|
||||
*
|
||||
* @returns {import('@ldapjs/asn1').BerReader}
|
||||
*/
|
||||
toBer () {
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence()
|
||||
writer.writeEnumeration(this.#operation)
|
||||
|
||||
const attrBer = this.#modification.toBer()
|
||||
writer.appendBuffer(attrBer.buffer)
|
||||
writer.endSequence()
|
||||
|
||||
return new BerReader(writer.buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link pojo}.
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
toJSON () {
|
||||
return this.pojo
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link Change} to a `target` object.
|
||||
*
|
||||
* @example
|
||||
* const change = new Change({
|
||||
* operation: 'add',
|
||||
* modification: {
|
||||
* type: 'cn',
|
||||
* values: ['new']
|
||||
* }
|
||||
* })
|
||||
* const target = {
|
||||
* cn: ['old']
|
||||
* }
|
||||
* Change.apply(change, target)
|
||||
* // target = { cn: ['old', 'new'] }
|
||||
*
|
||||
* @param {Change} change The change to apply.
|
||||
* @param {object} target The object to modify. This object will be mutated
|
||||
* by the function. It should have properties that match the `modification`
|
||||
* of the change.
|
||||
* @param {boolean} scalar When `true`, will convert single-item arrays
|
||||
* to scalar values. Default: `false`.
|
||||
*
|
||||
* @returns {object} The mutated `target`.
|
||||
*
|
||||
* @throws When the `change` is not an instance of {@link Change}.
|
||||
*/
|
||||
static apply (change, target, scalar = false) {
|
||||
if (Change.isChange(change) === false) {
|
||||
throw Error('change must be an instance of Change')
|
||||
}
|
||||
|
||||
const type = change.modification.type
|
||||
const values = change.modification.values
|
||||
|
||||
let data = target[type]
|
||||
if (data === undefined) {
|
||||
data = []
|
||||
} else if (Array.isArray(data) === false) {
|
||||
data = [data]
|
||||
}
|
||||
|
||||
switch (change.operation) {
|
||||
case 'add': {
|
||||
// Add only new unique entries.
|
||||
const newValues = values.filter(v => data.indexOf(v) === -1)
|
||||
Array.prototype.push.apply(data, newValues)
|
||||
break
|
||||
}
|
||||
|
||||
case 'delete': {
|
||||
data = data.filter(v => values.indexOf(v) === -1)
|
||||
if (data.length === 0) {
|
||||
// An empty list indicates the attribute should be removed
|
||||
// completely.
|
||||
delete target[type]
|
||||
return target
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'replace': {
|
||||
if (values.length === 0) {
|
||||
// A new value set that is empty is a delete.
|
||||
delete target[type]
|
||||
return target
|
||||
}
|
||||
data = values
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (scalar === true && data.length === 1) {
|
||||
// Replace array value with a scalar value if the modified set is
|
||||
// single valued and the operation calls for a scalar.
|
||||
target[type] = data[0]
|
||||
} else {
|
||||
target[type] = data
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an object is an instance of {@link Change}, or at least
|
||||
* resembles the shape of a {@link Change} object. A plain object will match
|
||||
* if it has a `modification` property that matches an `Attribute`,
|
||||
* an `operation` property that is a string or number, and has a `toBer`
|
||||
* method. An object that resembles a {@link Change} does not guarantee
|
||||
* compatibility. A `toString` check is much more accurate.
|
||||
*
|
||||
* @param {Change|object} change
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isChange (change) {
|
||||
if (Object.prototype.toString.call(change) === '[object LdapChange]') {
|
||||
return true
|
||||
}
|
||||
if (Object.prototype.toString.call(change) !== '[object Object]') {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
Attribute.isAttribute(change.modification) === true &&
|
||||
(typeof change.operation === 'string' || typeof change.operation === 'number')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two {@link Change} instance to determine the priority of the
|
||||
* changes relative to each other.
|
||||
*
|
||||
* @param {Change} change1
|
||||
* @param {Change} change2
|
||||
*
|
||||
* @returns {number} -1 for lower priority, 1 for higher priority, and 0
|
||||
* for equal priority in relation to `change1`, e.g. -1 would mean `change`
|
||||
* has lower priority than `change2`.
|
||||
*
|
||||
* @throws When neither parameter resembles a {@link Change} object.
|
||||
*/
|
||||
static compare (change1, change2) {
|
||||
if (Change.isChange(change1) === false || Change.isChange(change2) === false) {
|
||||
throw Error('can only compare Change instances')
|
||||
}
|
||||
if (change1.operation < change2.operation) {
|
||||
return -1
|
||||
}
|
||||
if (change1.operation > change2.operation) {
|
||||
return 1
|
||||
}
|
||||
return Attribute.compare(change1.modification, change2.modification)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a BER into a new {@link Change} object.
|
||||
*
|
||||
* @param {import('@ldapjs/asn1').BerReader} ber The BER to process. It must
|
||||
* be at an offset that starts a new change sequence. The reader will be
|
||||
* advanced to the end of the change sequence by this method.
|
||||
*
|
||||
* @returns {Change}
|
||||
*
|
||||
* @throws When there is an error processing the BER.
|
||||
*/
|
||||
static fromBer (ber) {
|
||||
ber.readSequence()
|
||||
const operation = ber.readEnumeration()
|
||||
const modification = Attribute.fromBer(ber)
|
||||
return new Change({ operation, modification })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Change
|
||||
422
node_modules/@ldapjs/change/index.test.js
generated
vendored
Normal file
422
node_modules/@ldapjs/change/index.test.js
generated
vendored
Normal file
@ -0,0 +1,422 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerReader } = require('@ldapjs/asn1')
|
||||
const Attribute = require('@ldapjs/attribute')
|
||||
const Change = require('./index')
|
||||
|
||||
tap.test('constructor', t => {
|
||||
t.test('throws for bad operation', async t => {
|
||||
t.throws(
|
||||
() => new Change({ operation: 'bad' }),
|
||||
Error('invalid operation type: bad')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('throws for bad modification', async t => {
|
||||
t.throws(
|
||||
() => new Change({ modification: 'bad' }),
|
||||
Error('modification must be an Attribute')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('creates an instance', async t => {
|
||||
const change = new Change({
|
||||
modification: new Attribute()
|
||||
})
|
||||
t.equal(change.operation, 'add')
|
||||
t.type(change.modification, Attribute)
|
||||
t.equal(Object.prototype.toString.call(change), '[object LdapChange]')
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('modification', t => {
|
||||
t.test('gets', async t => {
|
||||
const attr = new Attribute()
|
||||
const change = new Change({ modification: attr })
|
||||
t.equal(change.modification, attr)
|
||||
})
|
||||
|
||||
t.test('sets', async t => {
|
||||
const attr1 = new Attribute()
|
||||
const attr2 = new Attribute()
|
||||
const change = new Change({ modification: attr1 })
|
||||
t.equal(change.modification, attr1)
|
||||
change.modification = attr2
|
||||
t.equal(change.modification, attr2)
|
||||
t.not(attr1, attr2)
|
||||
})
|
||||
|
||||
t.test('throws if value is not attribute-like', async t => {
|
||||
const change = new Change({ modification: new Attribute() })
|
||||
t.throws(
|
||||
() => { change.modification = { foo: 'foo' } },
|
||||
Error('modification must be an Attribute')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('converts attribute-like to Attribute', async t => {
|
||||
const change = new Change({
|
||||
modification: {
|
||||
type: 'dn=foo,dc=example,dc=com',
|
||||
values: []
|
||||
}
|
||||
})
|
||||
t.equal(
|
||||
Object.prototype.toString.call(change.modification),
|
||||
'[object LdapAttribute]'
|
||||
)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('.operation', t => {
|
||||
const attr = new Attribute()
|
||||
const change = new Change({ modification: attr })
|
||||
|
||||
t.test('throws for unrecognized operation', async t => {
|
||||
t.throws(
|
||||
() => { change.operation = 'bad' },
|
||||
Error('invalid operation type: bad')
|
||||
)
|
||||
t.throws(
|
||||
() => { change.operation = 0xff },
|
||||
Error('invalid operation type: 0xff')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('sets and gets', async t => {
|
||||
change.operation = 0
|
||||
t.equal(change.operation, 'add')
|
||||
change.operation = 'add'
|
||||
t.equal(change.operation, 'add')
|
||||
|
||||
change.operation = 1
|
||||
t.equal(change.operation, 'delete')
|
||||
change.operation = 'delete'
|
||||
t.equal(change.operation, 'delete')
|
||||
|
||||
change.operation = 2
|
||||
t.equal(change.operation, 'replace')
|
||||
change.operation = 'replace'
|
||||
t.equal(change.operation, 'replace')
|
||||
|
||||
change.operation = 'Replace'
|
||||
t.equal(change.operation, 'replace')
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('.pojo', t => {
|
||||
t.test('returns a plain object', async t => {
|
||||
const change = new Change({
|
||||
modification: new Attribute()
|
||||
})
|
||||
const expected = {
|
||||
operation: 'add',
|
||||
modification: {
|
||||
type: '',
|
||||
values: []
|
||||
}
|
||||
}
|
||||
t.strictSame(change.pojo, expected)
|
||||
t.strictSame(change.toJSON(), expected)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('serializes to ber', async t => {
|
||||
const expected = Buffer.from([
|
||||
0x30, 0x15, // sequence, 21 bytes
|
||||
0x0a, 0x01, 0x00, // enumerated value 0
|
||||
0x30, 0x10, // sequence, 16 bytes
|
||||
0x04, 0x02, // string, 2 bytes
|
||||
0x63, 0x6e, // 'cn'
|
||||
0x31, 0x0a, // sequence of strings, 10 bytes
|
||||
0x04, 0x03, // string, 3 bytes
|
||||
0x66, 0x6f, 0x6f, // 'foo'
|
||||
0x04, 0x03, // string 3 bytes
|
||||
0x62, 0x61, 0x72
|
||||
])
|
||||
const change = new Change({
|
||||
modification: {
|
||||
type: 'cn',
|
||||
values: ['foo', 'bar']
|
||||
}
|
||||
})
|
||||
const ber = change.toBer()
|
||||
t.equal(expected.compare(ber.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#apply', t => {
|
||||
t.test('throws if change is not a Change', async t => {
|
||||
t.throws(
|
||||
() => Change.apply({}, {}),
|
||||
Error('change must be an instance of Change')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('applies to a target with no type', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = {}
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['new']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('applies to a target with a scalar type', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = { cn: 'old' }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('applies to a target with an array type', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = { cn: ['old'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('add operation adds only new values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new', 'foo']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = { cn: ['old', 'new'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new', 'foo']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('delete operation removes property', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'delete',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['new'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {})
|
||||
})
|
||||
|
||||
t.test('delete operation removes values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['remove_me']
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'delete',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['remove_me', 'keep_me'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['keep_me']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('replace removes empty set', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: []
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'replace',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['old'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {})
|
||||
})
|
||||
|
||||
t.test('replace removes values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new_set']
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'replace',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['old_set'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['new_set']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('scalar option works for new single values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = {}
|
||||
Change.apply(change, target, true)
|
||||
t.strictSame(target, {
|
||||
cn: 'new'
|
||||
})
|
||||
})
|
||||
|
||||
t.test('scalar option is ignored for multiple values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = {
|
||||
cn: ['old']
|
||||
}
|
||||
Change.apply(change, target, true)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new']
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#isChange', t => {
|
||||
t.test('true for instance', async t => {
|
||||
const change = new Change({ modification: new Attribute() })
|
||||
t.equal(Change.isChange(change), true)
|
||||
})
|
||||
|
||||
t.test('false for non-object', async t => {
|
||||
t.equal(Change.isChange([]), false)
|
||||
})
|
||||
|
||||
t.test('true for shape match', async t => {
|
||||
const change = {
|
||||
operation: 'add',
|
||||
modification: {
|
||||
type: '',
|
||||
values: []
|
||||
}
|
||||
}
|
||||
t.equal(Change.isChange(change), true)
|
||||
|
||||
change.operation = 0
|
||||
change.modification = new Attribute()
|
||||
t.equal(Change.isChange(change), true)
|
||||
})
|
||||
|
||||
t.test('false for shape mis-match', async t => {
|
||||
const change = {
|
||||
operation: 'add',
|
||||
mod: {
|
||||
type: '',
|
||||
values: []
|
||||
}
|
||||
}
|
||||
t.equal(Change.isChange(change), false)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#compare', t => {
|
||||
t.test('throws if params are not changes', async t => {
|
||||
const change = new Change({ modification: new Attribute() })
|
||||
const expected = Error('can only compare Change instances')
|
||||
t.throws(
|
||||
() => Change.compare({}, change),
|
||||
expected
|
||||
)
|
||||
t.throws(
|
||||
() => Change.compare(change, {}),
|
||||
expected
|
||||
)
|
||||
})
|
||||
|
||||
t.test('orders add first', async t => {
|
||||
const change1 = new Change({ modification: new Attribute() })
|
||||
const change2 = new Change({
|
||||
operation: 'delete',
|
||||
modification: new Attribute()
|
||||
})
|
||||
|
||||
t.equal(Change.compare(change1, change2), -1)
|
||||
|
||||
change2.operation = 'replace'
|
||||
t.equal(Change.compare(change1, change2), -1)
|
||||
})
|
||||
|
||||
t.test('orders delete above add', async t => {
|
||||
const change1 = new Change({ modification: new Attribute() })
|
||||
const change2 = new Change({
|
||||
operation: 'delete',
|
||||
modification: new Attribute()
|
||||
})
|
||||
|
||||
t.equal(Change.compare(change2, change1), 1)
|
||||
})
|
||||
|
||||
t.test('orders by attribute for same operation', async t => {
|
||||
const change1 = new Change({ modification: new Attribute() })
|
||||
const change2 = new Change({ modification: new Attribute() })
|
||||
t.equal(Change.compare(change1, change2), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#fromBer', t => {
|
||||
t.test('creates instance', async t => {
|
||||
const bytes = [
|
||||
0x30, 0x15, // sequence, 21 bytes
|
||||
0x0a, 0x01, 0x00, // enumerated value 0
|
||||
0x30, 0x10, // sequence, 16 bytes
|
||||
0x04, 0x02, // string, 2 bytes
|
||||
0x63, 0x6e, // 'cn'
|
||||
0x31, 0x0a, // sequence of strings, 10 bytes
|
||||
0x04, 0x03, // string, 3 bytes
|
||||
0x66, 0x6f, 0x6f, // 'foo'
|
||||
0x04, 0x03, // string 3 bytes
|
||||
0x62, 0x61, 0x72
|
||||
]
|
||||
const reader = new BerReader(Buffer.from(bytes))
|
||||
const change = Change.fromBer(reader)
|
||||
t.strictSame(change.pojo, {
|
||||
operation: 'add',
|
||||
modification: {
|
||||
type: 'cn',
|
||||
values: ['foo', 'bar']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
43
node_modules/@ldapjs/change/package.json
generated
vendored
Normal file
43
node_modules/@ldapjs/change/package.json
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"originalAuthor": "Patrick Mooney",
|
||||
"originalContributors": [
|
||||
"Mark Cavage <mcavage@gmail.com>",
|
||||
"Cody Peter Mello <cody.mello@joyent.com>"
|
||||
],
|
||||
"name": "@ldapjs/change",
|
||||
"homepage": "https://github.com/ldapjs/change",
|
||||
"description": "API for handling LDAP change objects",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:ldapjs/change.git"
|
||||
},
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "2.0.0",
|
||||
"@ldapjs/attribute": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fastify/pre-commit": "^2.0.2",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-config-standard": "^17.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-n": "^15.6.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"tap": "^16.3.4"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"lint:ci": "eslint .",
|
||||
"test": "tap --no-coverage-report",
|
||||
"test:cov": "tap",
|
||||
"test:cov:html": "tap --coverage-report=html",
|
||||
"test:watch": "tap -w --no-coverage-report"
|
||||
},
|
||||
"precommit": [
|
||||
"lint",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user