UNPKG

@ldapjs/messages

Version:

API for creating and parsing LDAP messages

199 lines (178 loc) 4.87 kB
'use strict' const LdapMessage = require('../ldap-message') const Attribute = require('@ldapjs/attribute') const { operations } = require('@ldapjs/protocol') const { DN } = require('@ldapjs/dn') /** * Implements the search result entry message as described in * https://www.rfc-editor.org/rfc/rfc4511.html#section-4.5.2. */ class SearchResultEntry extends LdapMessage { /** * Path to the LDAP object. * * @type {import('@ldapjs/dn').DN} */ #objectName /** * A set of attribute objects. * * @type {import('@ldapjs/attribute')[]} */ #attributes = [] /** * @typedef {LdapMessageOptions} SearchResultEntryOptions * @property {string | import('@ldapjs/dn').DN} [objectName=''] The path to * the LDAP object. * @property {import('@ldapjs/attribute')[]} attributes A set of attributes * to store at the `entry` path. */ /** * @param {SearchResultEntryOptions} [options] * * @throws When the provided attributes list is invalid or the object name * is not a valid LdapDn object or DN string. */ constructor (options = {}) { options.protocolOp = operations.LDAP_RES_SEARCH_ENTRY super(options) this.objectName = options.objectName ?? '' this.attributes = options.attributes ?? [] } /** * Alias of {@link objectName}. * * @type {string} */ get _dn () { return this.#objectName } /** * The name of the request type. * * @type {string} */ get type () { return 'SearchResultEntry' } /** * Get a copy of the attributes associated with the request. * * @returns {import('@ldapjs/attribute')[]} */ get attributes () { return this.#attributes.slice(0) } /** * Set the attributes to be added to the entry. Replaces any existing * attributes. * * @param {object[] | import('@ldapjs/attribute')[]} attrs * * @throws If the input is not an array, or any element is not an * {@link Attribute} or attribute-like object. */ set attributes (attrs) { if (Array.isArray(attrs) === false) { throw Error('attrs must be an array') } const newAttrs = [] for (const attr of attrs) { if (Attribute.isAttribute(attr) === false) { throw Error('attr must be an Attribute instance or Attribute-like object') } if (Object.prototype.toString.call(attr) !== '[object LdapAttribute]') { newAttrs.push(new Attribute(attr)) continue } newAttrs.push(attr) } this.#attributes = newAttrs } /** * The path to the LDAP entry that matched the search. * * @returns {import('@ldapjs/dn').DN} */ get objectName () { return this.#objectName } /** * Set the path to the LDAP entry that matched the search. * * @param {string | import('@ldapjs/dn').DN} value * * @throws When the input is invalid. */ set objectName (value) { if (typeof value === 'string') { this.#objectName = DN.fromString(value) } else if (Object.prototype.toString.call(value) === '[object LdapDn]') { this.#objectName = value } else { throw Error('objectName must be a DN string or an instance of LdapDn') } } /** * Internal use only. * * @param {import('@ldapjs/asn1').BerWriter} ber * * @returns {import('@ldapjs/asn1').BerWriter} */ _toBer (ber) { ber.startSequence(operations.LDAP_RES_SEARCH_ENTRY) ber.writeString(this.#objectName.toString()) ber.startSequence() for (const attr of this.#attributes) { const attrBer = attr.toBer() ber.appendBuffer(attrBer.buffer) } ber.endSequence() ber.endSequence() return ber } /** * Internal use only. * * @param {object} * * @returns {object} */ _pojo (obj = {}) { obj.objectName = this.#objectName.toString() obj.attributes = [] for (const attr of this.#attributes) { obj.attributes.push(attr.pojo) } return obj } /** * Implements the standardized `parseToPojo` method. * * @see LdapMessage.parseToPojo * * @param {import('@ldapjs/asn1').BerReader} ber * * @returns {object} */ static parseToPojo (ber) { const protocolOp = ber.readSequence() if (protocolOp !== operations.LDAP_RES_SEARCH_ENTRY) { const op = protocolOp.toString(16).padStart(2, '0') throw Error(`found wrong protocol operation: 0x${op}`) } const objectName = ber.readString() const attributes = [] // Advance to the first attribute sequence in the set // of attribute sequences. ber.readSequence() const endOfAttributesPos = ber.offset + ber.length while (ber.offset < endOfAttributesPos) { const attribute = Attribute.fromBer(ber) attributes.push(attribute) } return { protocolOp, objectName, attributes } } } module.exports = SearchResultEntry