UNPKG

@ldapjs/messages

Version:

API for creating and parsing LDAP messages

317 lines (275 loc) 7.76 kB
'use strict' const tap = require('tap') const Attribute = require('@ldapjs/attribute') const { BerReader, BerWriter } = require('@ldapjs/asn1') const { DN } = require('@ldapjs/dn') const AddRequest = require('./add-request') const { addRequestBytes } = require('./_fixtures/message-byte-arrays') tap.test('basic', t => { t.test('constructor no args', async t => { const req = new AddRequest() t.strictSame(req.pojo, { messageId: 1, protocolOp: 0x68, type: 'AddRequest', entry: null, attributes: [], controls: [] }) }) t.test('constructor with args', async t => { const req = new AddRequest({ entry: 'dn=foo,dc=example,dc=com', attributes: [{ type: 'cn', values: ['foo'] }] }) t.strictSame(req.pojo, { messageId: 1, protocolOp: 0x68, type: 'AddRequest', entry: 'dn=foo,dc=example,dc=com', attributes: [{ type: 'cn', values: ['foo'] }], controls: [] }) }) t.end() }) tap.test('.attributes', t => { t.test('returns a copy of the attributes', async t => { const inputAttrs = [{ type: 'cn', values: ['foo'] }] const req = new AddRequest({ entry: 'cn=foo', attributes: inputAttrs }) const attrs = req.attributes t.not(attrs, inputAttrs) t.equal(attrs.length, inputAttrs.length) }) t.test('replaces attributes list', async t => { const req = new AddRequest({ entry: 'cn=foo', attributes: [new Attribute({ type: 'cn', values: ['foo'] })] }) t.strictSame(req.attributes[0].pojo, { type: 'cn', values: ['foo'] }) req.attributes = [new Attribute({ type: 'sn', values: ['bar'] })] t.strictSame(req.attributes[0].pojo, { type: 'sn', values: ['bar'] }) }) t.test('throws if not an array', async t => { const input = { type: 'cn', values: ['foo'] } t.throws( () => new AddRequest({ entry: 'cn=foo', attributes: input }), Error('attrs must be an array') ) }) t.test('throws if attribute is invalid', async t => { const input = [{ type: 42, values: ['foo'] }] t.throws( () => new AddRequest({ entry: 'cn=foo', attributes: input }), Error('attr must be an Attribute instance or Attribute-like object') ) }) t.end() }) tap.test('.entry', t => { t.test('gets and sets', async t => { let req = new AddRequest({ entry: 'cn=foo' }) t.equal(req.entry.toString(), 'cn=foo') t.equal(req._dn.toString(), 'cn=foo') req.entry = 'sn=bar' t.equal(req.entry.toString(), 'sn=bar') t.equal(req._dn.toString(), 'sn=bar') req.entry = DN.fromString('cn=baz') t.equal(req.entry.toString(), 'cn=baz') req = new AddRequest() t.equal(req.entry, null) }) t.test('throws for bad value', async t => { const req = new AddRequest() t.throws( () => { req.entry = { cn: 'foo' } }, 'entry must be a valid DN string or instance of LdapDn' ) }) t.end() }) tap.test('addAttribute', t => { t.test('throws for invalid input', async t => { const req = new AddRequest({ entry: 'cn=foo' }) t.throws( () => req.addAttribute({ type: 'foo', values: ['foo'] }), Error('attr must be an instance of Attribute') ) }) t.test('adds an attribute', async t => { const req = new AddRequest({ entry: 'cn=foo' }) req.addAttribute(new Attribute({ type: 'bar', values: ['baz'] })) t.strictSame(req.pojo, { messageId: 1, protocolOp: 0x68, type: 'AddRequest', entry: 'cn=foo', attributes: [{ type: 'bar', values: ['baz'] }], controls: [] }) }) t.end() }) tap.test('attributeNames', t => { t.test('returns the names list', async t => { const req = new AddRequest({ entry: 'cn=foo', attributes: [ new Attribute({ type: 'bar' }), new Attribute({ type: 'baz' }), new Attribute({ type: 'foobar' }), new Attribute({ type: 'barfoo' }) ] }) t.strictSame(req.attributeNames(), [ 'bar', 'baz', 'foobar', 'barfoo' ]) }) t.end() }) tap.test('getAttribute', t => { t.test('throws for invalid parameter', async t => { const req = new AddRequest({ entry: 'cn=foo' }) t.throws( () => req.getAttribute(42), Error('attributeName must be a string') ) }) t.test('returns null for not found', async t => { const req = new AddRequest({ entry: 'cn=foo' }) t.equal(req.getAttribute('bar'), null) }) t.test('returns the correct attribute', async t => { const req = new AddRequest({ entry: 'cn=foo', attributes: [ new Attribute({ type: 'bar' }), new Attribute({ type: 'baz', values: ['baz', 'baz', 'baz'] }), new Attribute({ type: 'foobar' }), new Attribute({ type: 'barfoo' }) ] }) const attr = req.getAttribute('baz') t.strictSame(attr.pojo, { type: 'baz', values: ['baz', 'baz', 'baz'] }) }) t.end() }) tap.test('indexOf', t => { t.test('throws for invalid parameter', async t => { const req = new AddRequest({ entry: 'cn=foo' }) t.throws( () => req.indexOf(42), Error('attributeName must be a string') ) }) t.test('finds an attribute', async t => { const req = new AddRequest({ entry: 'cn=foo', attributes: [ new Attribute({ type: 'bar' }), new Attribute({ type: 'baz' }), new Attribute({ type: 'foobar' }), new Attribute({ type: 'barfoo' }) ] }) t.equal(req.indexOf('foobar'), 2) }) t.test('returns for not found', async t => { const req = new AddRequest({ entry: 'cn=foo', attributes: [ new Attribute({ type: 'bar' }), new Attribute({ type: 'baz' }), new Attribute({ type: 'foobar' }), new Attribute({ type: 'barfoo' }) ] }) t.equal(req.indexOf('zifbang'), -1) }) t.end() }) tap.test('_toBer', t => { tap.test('converts instance to BER', async t => { const req = new AddRequest({ entry: 'dc=example,dc=com', attributes: [ new Attribute({ type: 'objectclass', values: ['top', 'domain'] }), new Attribute({ type: 'dc', values: ['example'] }) ] }) const writer = new BerWriter() req._toBer(writer) t.equal( Buffer.from(addRequestBytes.slice(5)).compare(writer.buffer), 0 ) }) t.end() }) tap.test('_pojo', t => { t.test('returns a pojo representation', async t => { const req = new AddRequest({ entry: 'cn=foo', attributes: [{ type: 'bar', values: ['baz'] }] }) t.strictSame(req._pojo(), { entry: 'cn=foo', attributes: [{ type: 'bar', values: ['baz'] }] }) }) t.end() }) tap.test('#parseToPojo', t => { t.test('throws if operation incorrect', async t => { const reqBuffer = Buffer.from(addRequestBytes) reqBuffer[5] = 0x61 const reader = new BerReader(reqBuffer) reader.readSequence() reader.readInt() t.throws( () => AddRequest.parseToPojo(reader), Error('found wrong protocol operation: 0x61') ) }) t.test('returns a pojo representation', async t => { const reqBuffer = Buffer.from(addRequestBytes) const reader = new BerReader(reqBuffer) reader.readSequence() reader.readInt() const pojo = AddRequest.parseToPojo(reader) t.equal(pojo.protocolOp, 0x68) t.equal(pojo.entry, 'dc=example,dc=com') t.strictSame(pojo.attributes[0].pojo, { type: 'objectclass', values: ['top', 'domain'] }) t.strictSame(pojo.attributes[1].pojo, { type: 'dc', values: ['example'] }) }) t.end() })