UNPKG

@ldapjs/messages

Version:

API for creating and parsing LDAP messages

190 lines (164 loc) 4.36 kB
'use strict' const LdapMessage = require('../ldap-message') const { operations } = require('@ldapjs/protocol') const partIsNotNumeric = part => /^\d+$/.test(part) === false /** * Determines if a passed in string is a dotted decimal string. * * Copied from `@ldapjs/dn`. * * @param {string} value * * @returns {boolean} */ function isDottedDecimal (value) { if (typeof value !== 'string') return false const parts = value.split('.') const nonNumericParts = parts.filter(partIsNotNumeric) return nonNumericParts.length === 0 } /** * Implements the intermediate response message as described in * https://www.rfc-editor.org/rfc/rfc4511.html#section-4.13. * * TODO: actual implementations of this, e.g. RFC 4533 §2.5, seem to encode * sequences in the responseValue. That means this needs a more robust * implementation like is found in the ExtensionResponse implementation (i.e. * detection of recognized OIDs and specific sub-implementations). As of now, * this implementation follows the baseline spec without any sub-implementations. */ class IntermediateResponse extends LdapMessage { #responseName #responseValue /** * @typedef {LdapMessageOptions} IntermediateResponseOptions * @property {string} responseName * @property {string} responseValue */ /** * @param {IntermediateResponseOptions} options */ constructor (options = {}) { options.protocolOp = operations.LDAP_RES_INTERMEDIATE super(options) this.responseName = options.responseName ?? null this.responseValue = options.responseValue ?? null } /** * The name of the request type. * * @type {string} */ get type () { return 'IntermediateResponse' } /** * The numeric OID that identifies the type of intermediate response. * * @returns {string | undefined} */ get responseName () { return this.#responseName } /** * Define the numeric OID that identifies the type of intermediate response. * * @param {string | null} value * * @throws For an invalid value. */ set responseName (value) { if (value === null) return if (isDottedDecimal(value) === false) { throw Error('responseName must be a numeric OID') } this.#responseName = value } /** * The value for the intermidate response if any. * * @returns {string | undefined} */ get responseValue () { return this.#responseValue } /** * Define the value for the intermediate response. * * @param {string | null} value * * @throws For an invalid value. */ set responseValue (value) { if (value === null) return if (typeof value !== 'string') { throw Error('responseValue must be a string') } this.#responseValue = value } /** * Internal use only. * * @param {import('@ldapjs/asn1').BerWriter} ber * * @returns {import('@ldapjs/asn1').BerWriter} */ _toBer (ber) { ber.startSequence(operations.LDAP_RES_INTERMEDIATE) if (this.#responseName) { ber.writeString(this.#responseName, 0x80) } if (this.#responseValue) { ber.writeString(this.#responseValue, 0x81) } ber.endSequence() return ber } /** * Internal use only. * * @param {object} * * @returns {object} */ _pojo (obj = {}) { obj.responseName = this.#responseName obj.responseValue = this.#responseValue 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_INTERMEDIATE) { const op = protocolOp.toString(16).padStart(2, '0') throw Error(`found wrong protocol operation: 0x${op}`) } let responseName let responseValue let tag = ber.peek() switch (tag) { case 0x80: { responseName = ber.readString(tag) tag = ber.peek() /* istanbul ignore else */ if (tag === 0x81) { responseValue = ber.readString(tag) } break } case 0x81: { responseValue = ber.readString(tag) } } return { protocolOp, responseName, responseValue } } } module.exports = IntermediateResponse