First commit
This commit is contained in:
282
node_modules/@ldapjs/messages/lib/ldap-message.js
generated
vendored
Normal file
282
node_modules/@ldapjs/messages/lib/ldap-message.js
generated
vendored
Normal file
@ -0,0 +1,282 @@
|
||||
'use strict'
|
||||
|
||||
const { BerReader, BerWriter } = require('@ldapjs/asn1')
|
||||
const warning = require('./deprecations')
|
||||
|
||||
/**
|
||||
* Implements a base LDAP message as defined in
|
||||
* https://www.rfc-editor.org/rfc/rfc4511.html#section-4.1.1.
|
||||
*/
|
||||
class LdapMessage {
|
||||
#messageId = 0
|
||||
#protocolOp
|
||||
#controls = []
|
||||
|
||||
/**
|
||||
* @typedef {object} LdapMessageOptions
|
||||
* @property {number} [messageId=1] An identifier for the message.
|
||||
* @property {number} [protocolOp] The tag for the message operation.
|
||||
* @property {import('@ldapjs/controls').Control[]} [controls] A set of LDAP
|
||||
* controls to send with the message. See the `@ldapjs/controls` package.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {LdapMessageOptions} [options]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
this.#messageId = parseInt(options.messageId ?? options.messageID ?? '1', 10)
|
||||
if (options.messageID !== undefined) {
|
||||
warning.emit('LDAP_MESSAGE_DEP_001')
|
||||
}
|
||||
|
||||
if (typeof options.protocolOp === 'number') {
|
||||
this.#protocolOp = options.protocolOp
|
||||
}
|
||||
|
||||
this.controls = options.controls ?? []
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag] () {
|
||||
return 'LdapMessage'
|
||||
}
|
||||
|
||||
/**
|
||||
* A copy of the list of controls that will be sent with the request.
|
||||
*
|
||||
* @returns {import('@ldapjs/controls').Control[]}
|
||||
*/
|
||||
get controls () {
|
||||
return this.#controls.slice(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the list of controls that will be sent with the request. Any
|
||||
* existing controls will be discarded.
|
||||
*
|
||||
* @param {import('@ldapjs/controls').Control[]} values
|
||||
*
|
||||
* @throws When a control value is invalid.
|
||||
*/
|
||||
set controls (values) {
|
||||
if (Array.isArray(values) !== true) {
|
||||
throw Error('controls must be an array')
|
||||
}
|
||||
const newControls = []
|
||||
for (const val of values) {
|
||||
if (Object.prototype.toString.call(val) !== '[object LdapControl]') {
|
||||
throw Error('control must be an instance of LdapControl')
|
||||
}
|
||||
newControls.push(val)
|
||||
}
|
||||
this.#controls = newControls
|
||||
}
|
||||
|
||||
/**
|
||||
* The message identifier.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get id () {
|
||||
return this.#messageId
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the message identifier for the request.
|
||||
*
|
||||
* @param {number} value
|
||||
*/
|
||||
set id (value) {
|
||||
if (Number.isInteger(value) === false) {
|
||||
throw Error('id must be an integer')
|
||||
}
|
||||
this.#messageId = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link id}.
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
get messageId () {
|
||||
return this.id
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link id}.
|
||||
*
|
||||
* @param {number} value
|
||||
*/
|
||||
set messageId (value) {
|
||||
this.id = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link id}.
|
||||
*
|
||||
* @returns {number}
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
get messageID () {
|
||||
warning.emit('LDAP_MESSAGE_DEP_001')
|
||||
return this.id
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link id}.
|
||||
*
|
||||
* @param {number} value
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
set messageID (value) {
|
||||
warning.emit('LDAP_MESSAGE_DEP_001')
|
||||
this.id = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Message type specific. Each message type must implement a `_dn` property
|
||||
* that provides this value.
|
||||
*
|
||||
* @type {import('@ldapjs/dn').DN}
|
||||
*/
|
||||
get dn () {
|
||||
return this._dn
|
||||
}
|
||||
|
||||
/**
|
||||
* The LDAP protocol operation code for the message.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get protocolOp () {
|
||||
return this.#protocolOp
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the message class.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
get type () {
|
||||
return 'LdapMessage'
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link pojo} instead.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
get json () {
|
||||
warning.emit('LDAP_MESSAGE_DEP_002')
|
||||
return this.pojo
|
||||
}
|
||||
|
||||
/**
|
||||
* A serialized representation of the message as a plain JavaScript object.
|
||||
* Specific message types must implement the `_pojo(obj)` method. The passed
|
||||
* in `obj` must be extended with the specific message's unique properties
|
||||
* and returned as the result.
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
get pojo () {
|
||||
let result = {
|
||||
messageId: this.id,
|
||||
protocolOp: this.#protocolOp,
|
||||
type: this.type
|
||||
}
|
||||
|
||||
if (typeof this._pojo === 'function') {
|
||||
result = this._pojo(result)
|
||||
}
|
||||
|
||||
result.controls = this.#controls.map(c => c.pojo)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
addControl (control) {
|
||||
this.#controls.push(control)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an {@link LdapMessage} object into a set of BER bytes that can
|
||||
* be sent across the wire. Specific message implementations must implement
|
||||
* the `_toBer(ber)` method. This method will write its unique sequence(s)
|
||||
* to the passed in `ber` object.
|
||||
*
|
||||
* @returns {import('@ldapjs/asn1').BerReader}
|
||||
*/
|
||||
toBer () {
|
||||
if (typeof this._toBer !== 'function') {
|
||||
throw Error(`${this.type} does not implement _toBer`)
|
||||
}
|
||||
|
||||
const writer = new BerWriter()
|
||||
writer.startSequence()
|
||||
writer.writeInt(this.id)
|
||||
|
||||
this._toBer(writer)
|
||||
|
||||
if (this.#controls.length > 0) {
|
||||
writer.startSequence(0xa0)
|
||||
for (const control of this.#controls) {
|
||||
control.toBer(writer)
|
||||
}
|
||||
writer.endSequence()
|
||||
}
|
||||
|
||||
writer.endSequence()
|
||||
return new BerReader(writer.buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message into a JSON representation.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
toString () {
|
||||
return JSON.stringify(this.pojo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a BER into a message object. The offset of the BER _must_ point
|
||||
* to the start of an LDAP Message sequence. That is, the first few bytes
|
||||
* must indicate:
|
||||
*
|
||||
* 1. a sequence tag and how many bytes are in that sequence
|
||||
* 2. an integer representing the message identifier
|
||||
* 3. a protocol operation, e.g. BindRequest, and the number of bytes in
|
||||
* that operation
|
||||
*
|
||||
* @param {import('@ldapjs/asn1').BerReader} ber
|
||||
*
|
||||
* @returns {LdapMessage}
|
||||
*/
|
||||
static parse (ber) {
|
||||
// We must require here because `parseToMessage` imports subclasses
|
||||
// that need `LdapMessage` to be defined. If we try importing earlier,
|
||||
// then `LdapMessage` will not be available, and we will get errors about
|
||||
// trying to subclass null objects.
|
||||
return require('./parse-to-message')(ber)
|
||||
}
|
||||
|
||||
/**
|
||||
* When invoked on specific message types, e.g. {@link BindRequest}, this
|
||||
* method will parse a BER into a plain JavaScript object that is usable as
|
||||
* an options object for constructing that specific message object.
|
||||
*
|
||||
* @param {import('@ldapjs/asn1').BerReader} ber A BER to parse. The reader
|
||||
* offset must point to the start of a valid sequence, i.e. the "tag" byte
|
||||
* in the TLV tuple, that represents the message to be parsed. For example,
|
||||
* in a {@link BindRequest} the starting sequence and message identifier must
|
||||
* already be read such that the offset is at the protocol operation sequence
|
||||
* byte.
|
||||
*/
|
||||
static parseToPojo (ber) {
|
||||
throw Error('Use LdapMessage.parse, or a specific message type\'s parseToPojo, instead.')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LdapMessage
|
||||
Reference in New Issue
Block a user