First commit
This commit is contained in:
39
node_modules/ldapjs/lib/messages/index.js
generated
vendored
Normal file
39
node_modules/ldapjs/lib/messages/index.js
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||
|
||||
const messages = require('@ldapjs/messages')
|
||||
|
||||
const Parser = require('./parser')
|
||||
|
||||
const SearchResponse = require('./search_response')
|
||||
|
||||
/// --- API
|
||||
|
||||
module.exports = {
|
||||
|
||||
LDAPMessage: messages.LdapMessage,
|
||||
LDAPResult: messages.LdapResult,
|
||||
Parser,
|
||||
|
||||
AbandonRequest: messages.AbandonRequest,
|
||||
AbandonResponse: messages.AbandonResponse,
|
||||
AddRequest: messages.AddRequest,
|
||||
AddResponse: messages.AddResponse,
|
||||
BindRequest: messages.BindRequest,
|
||||
BindResponse: messages.BindResponse,
|
||||
CompareRequest: messages.CompareRequest,
|
||||
CompareResponse: messages.CompareResponse,
|
||||
DeleteRequest: messages.DeleteRequest,
|
||||
DeleteResponse: messages.DeleteResponse,
|
||||
ExtendedRequest: messages.ExtensionRequest,
|
||||
ExtendedResponse: messages.ExtensionResponse,
|
||||
ModifyRequest: messages.ModifyRequest,
|
||||
ModifyResponse: messages.ModifyResponse,
|
||||
ModifyDNRequest: messages.ModifyDnRequest,
|
||||
ModifyDNResponse: messages.ModifyDnResponse,
|
||||
SearchRequest: messages.SearchRequest,
|
||||
SearchEntry: messages.SearchResultEntry,
|
||||
SearchReference: messages.SearchResultReference,
|
||||
SearchResponse,
|
||||
UnbindRequest: messages.UnbindRequest
|
||||
|
||||
}
|
||||
249
node_modules/ldapjs/lib/messages/parser.js
generated
vendored
Normal file
249
node_modules/ldapjs/lib/messages/parser.js
generated
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const util = require('util')
|
||||
|
||||
const assert = require('assert-plus')
|
||||
const asn1 = require('@ldapjs/asn1')
|
||||
const logger = require('../logger')
|
||||
|
||||
const messages = require('@ldapjs/messages')
|
||||
const AbandonRequest = messages.AbandonRequest
|
||||
const AddRequest = messages.AddRequest
|
||||
const AddResponse = messages.AddResponse
|
||||
const BindRequest = messages.BindRequest
|
||||
const BindResponse = messages.BindResponse
|
||||
const CompareRequest = messages.CompareRequest
|
||||
const CompareResponse = messages.CompareResponse
|
||||
const DeleteRequest = messages.DeleteRequest
|
||||
const DeleteResponse = messages.DeleteResponse
|
||||
const ExtendedRequest = messages.ExtensionRequest
|
||||
const ExtendedResponse = messages.ExtensionResponse
|
||||
const ModifyRequest = messages.ModifyRequest
|
||||
const ModifyResponse = messages.ModifyResponse
|
||||
const ModifyDNRequest = messages.ModifyDnRequest
|
||||
const ModifyDNResponse = messages.ModifyDnResponse
|
||||
const SearchRequest = messages.SearchRequest
|
||||
const SearchEntry = messages.SearchResultEntry
|
||||
const SearchReference = messages.SearchResultReference
|
||||
const SearchResponse = require('./search_response')
|
||||
const UnbindRequest = messages.UnbindRequest
|
||||
const LDAPResult = messages.LdapResult
|
||||
|
||||
const Protocol = require('@ldapjs/protocol')
|
||||
|
||||
/// --- Globals
|
||||
|
||||
const BerReader = asn1.BerReader
|
||||
|
||||
/// --- API
|
||||
|
||||
function Parser (options = {}) {
|
||||
assert.object(options)
|
||||
|
||||
EventEmitter.call(this)
|
||||
|
||||
this.buffer = null
|
||||
this.log = options.log || logger
|
||||
}
|
||||
util.inherits(Parser, EventEmitter)
|
||||
|
||||
/**
|
||||
* The LDAP server/client implementations will receive data from a stream and feed
|
||||
* it into this method. This method will collect that data into an internal
|
||||
* growing buffer. As that buffer fills with enough data to constitute a valid
|
||||
* LDAP message, the data will be parsed, emitted as a message object, and
|
||||
* reset the buffer to account for any next message in the stream.
|
||||
*/
|
||||
Parser.prototype.write = function (data) {
|
||||
if (!data || !Buffer.isBuffer(data)) { throw new TypeError('data (buffer) required') }
|
||||
|
||||
let nextMessage = null
|
||||
const self = this
|
||||
|
||||
function end () {
|
||||
if (nextMessage) { return self.write(nextMessage) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
self.buffer = self.buffer ? Buffer.concat([self.buffer, data]) : data
|
||||
|
||||
let ber = new BerReader(self.buffer)
|
||||
|
||||
let foundSeq = false
|
||||
try {
|
||||
foundSeq = ber.readSequence()
|
||||
} catch (e) {
|
||||
this.emit('error', e)
|
||||
}
|
||||
|
||||
if (!foundSeq || ber.remain < ber.length) {
|
||||
// ENOTENOUGH
|
||||
return false
|
||||
} else if (ber.remain > ber.length) {
|
||||
// ETOOMUCH
|
||||
|
||||
// This is an odd branch. Basically, it is setting `nextMessage` to
|
||||
// a buffer that represents data part of a message subsequent to the one
|
||||
// being processed. It then re-creates `ber` as a representation of
|
||||
// the message being processed and advances its offset to the value
|
||||
// position of the TLV.
|
||||
|
||||
// Set `nextMessage` to the bytes subsequent to the current message's
|
||||
// value bytes. That is, slice from the byte immediately following the
|
||||
// current message's value bytes until the end of the buffer.
|
||||
nextMessage = self.buffer.slice(ber.offset + ber.length)
|
||||
|
||||
const currOffset = ber.offset
|
||||
ber = new BerReader(ber.buffer.subarray(0, currOffset + ber.length))
|
||||
ber.readSequence()
|
||||
|
||||
assert.equal(ber.remain, ber.length)
|
||||
}
|
||||
|
||||
// If we're here, ber holds the message, and nextMessage is temporarily
|
||||
// pointing at the next sequence of data (if it exists)
|
||||
self.buffer = null
|
||||
|
||||
let message
|
||||
try {
|
||||
if (Object.prototype.toString.call(ber) === '[object BerReader]') {
|
||||
// Parse the BER into a JavaScript object representation. The message
|
||||
// objects require the full sequence in order to construct the object.
|
||||
// At this point, we have already read the sequence tag and length, so
|
||||
// we need to rewind the buffer a bit. The `.sequenceToReader` method
|
||||
// does this for us.
|
||||
message = messages.LdapMessage.parse(ber.sequenceToReader())
|
||||
} else {
|
||||
// Bail here if peer isn't speaking protocol at all
|
||||
message = this.getMessage(ber)
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
return end()
|
||||
}
|
||||
|
||||
// TODO: find a better way to handle logging now that messages and the
|
||||
// server are decoupled. ~ jsumners 2023-02-17
|
||||
message.log = this.log
|
||||
} catch (e) {
|
||||
this.emit('error', e, message)
|
||||
return false
|
||||
}
|
||||
|
||||
this.emit('message', message)
|
||||
return end()
|
||||
}
|
||||
|
||||
Parser.prototype.getMessage = function (ber) {
|
||||
assert.ok(ber)
|
||||
|
||||
const self = this
|
||||
|
||||
const messageId = ber.readInt()
|
||||
const type = ber.readSequence()
|
||||
|
||||
let Message
|
||||
switch (type) {
|
||||
case Protocol.operations.LDAP_REQ_ABANDON:
|
||||
Message = AbandonRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_ADD:
|
||||
Message = AddRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_ADD:
|
||||
Message = AddResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_BIND:
|
||||
Message = BindRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_BIND:
|
||||
Message = BindResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_COMPARE:
|
||||
Message = CompareRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_COMPARE:
|
||||
Message = CompareResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_DELETE:
|
||||
Message = DeleteRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_DELETE:
|
||||
Message = DeleteResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_EXTENSION:
|
||||
Message = ExtendedRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_EXTENSION:
|
||||
Message = ExtendedResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_MODIFY:
|
||||
Message = ModifyRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_MODIFY:
|
||||
Message = ModifyResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_MODRDN:
|
||||
Message = ModifyDNRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_MODRDN:
|
||||
Message = ModifyDNResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_SEARCH:
|
||||
Message = SearchRequest
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_SEARCH_ENTRY:
|
||||
Message = SearchEntry
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_SEARCH_REF:
|
||||
Message = SearchReference
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_RES_SEARCH:
|
||||
Message = SearchResponse
|
||||
break
|
||||
|
||||
case Protocol.operations.LDAP_REQ_UNBIND:
|
||||
Message = UnbindRequest
|
||||
break
|
||||
|
||||
default:
|
||||
this.emit('error',
|
||||
new Error('Op 0x' + (type ? type.toString(16) : '??') +
|
||||
' not supported'),
|
||||
new LDAPResult({
|
||||
messageId,
|
||||
protocolOp: type || Protocol.operations.LDAP_RES_EXTENSION
|
||||
}))
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return new Message({
|
||||
messageId,
|
||||
log: self.log
|
||||
})
|
||||
}
|
||||
|
||||
/// --- Exports
|
||||
|
||||
module.exports = Parser
|
||||
122
node_modules/ldapjs/lib/messages/search_response.js
generated
vendored
Normal file
122
node_modules/ldapjs/lib/messages/search_response.js
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||
|
||||
const assert = require('assert-plus')
|
||||
|
||||
const Attribute = require('@ldapjs/attribute')
|
||||
const {
|
||||
SearchResultEntry: SearchEntry,
|
||||
SearchResultReference: SearchReference,
|
||||
SearchResultDone
|
||||
} = require('@ldapjs/messages')
|
||||
|
||||
const parseDN = require('@ldapjs/dn').DN.fromString
|
||||
|
||||
/// --- API
|
||||
|
||||
class SearchResponse extends SearchResultDone {
|
||||
attributes
|
||||
notAttributes
|
||||
sentEntries
|
||||
|
||||
constructor (options = {}) {
|
||||
super(options)
|
||||
|
||||
this.attributes = options.attributes ? options.attributes.slice() : []
|
||||
this.notAttributes = []
|
||||
this.sentEntries = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to send a SearchEntry back to the client.
|
||||
*
|
||||
* @param {Object} entry an instance of SearchEntry.
|
||||
* @param {Boolean} nofiltering skip filtering notAttributes and '_' attributes.
|
||||
* Defaults to 'false'.
|
||||
*/
|
||||
SearchResponse.prototype.send = function (entry, nofiltering) {
|
||||
if (!entry || typeof (entry) !== 'object') { throw new TypeError('entry (SearchEntry) required') }
|
||||
if (nofiltering === undefined) { nofiltering = false }
|
||||
if (typeof (nofiltering) !== 'boolean') { throw new TypeError('noFiltering must be a boolean') }
|
||||
|
||||
const self = this
|
||||
|
||||
const savedAttrs = {}
|
||||
let save = null
|
||||
if (entry instanceof SearchEntry || entry instanceof SearchReference) {
|
||||
if (!entry.messageId) { entry.messageId = this.messageId }
|
||||
if (entry.messageId !== this.messageId) {
|
||||
throw new Error('SearchEntry messageId mismatch')
|
||||
}
|
||||
} else {
|
||||
if (!entry.attributes) { throw new Error('entry.attributes required') }
|
||||
|
||||
const all = (self.attributes.indexOf('*') !== -1)
|
||||
// Filter attributes in a plain object according to the magic `_` prefix
|
||||
// and presence in `notAttributes`.
|
||||
Object.keys(entry.attributes).forEach(function (a) {
|
||||
const _a = a.toLowerCase()
|
||||
if (!nofiltering && _a.length && _a[0] === '_') {
|
||||
savedAttrs[a] = entry.attributes[a]
|
||||
delete entry.attributes[a]
|
||||
} else if (!nofiltering && self.notAttributes.indexOf(_a) !== -1) {
|
||||
savedAttrs[a] = entry.attributes[a]
|
||||
delete entry.attributes[a]
|
||||
} else if (all) {
|
||||
// do nothing
|
||||
} else if (self.attributes.length && self.attributes.indexOf(_a) === -1) {
|
||||
savedAttrs[a] = entry.attributes[a]
|
||||
delete entry.attributes[a]
|
||||
}
|
||||
})
|
||||
|
||||
save = entry
|
||||
entry = new SearchEntry({
|
||||
objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn,
|
||||
messageId: self.messageId,
|
||||
attributes: Attribute.fromObject(entry.attributes)
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.pojo)
|
||||
|
||||
this.connection.write(entry.toBer().buffer)
|
||||
this.sentEntries++
|
||||
|
||||
// Restore attributes
|
||||
Object.keys(savedAttrs).forEach(function (k) {
|
||||
save.attributes[k] = savedAttrs[k]
|
||||
})
|
||||
} catch (e) {
|
||||
this.log.warn(e, '%s failure to write message %j',
|
||||
this.connection.ldap.id, this.pojo)
|
||||
}
|
||||
}
|
||||
|
||||
SearchResponse.prototype.createSearchEntry = function (object) {
|
||||
assert.object(object)
|
||||
|
||||
const entry = new SearchEntry({
|
||||
messageId: this.messageId,
|
||||
objectName: object.objectName || object.dn,
|
||||
attributes: object.attributes ?? []
|
||||
})
|
||||
return entry
|
||||
}
|
||||
|
||||
SearchResponse.prototype.createSearchReference = function (uris) {
|
||||
if (!uris) { throw new TypeError('uris ([string]) required') }
|
||||
|
||||
if (!Array.isArray(uris)) { uris = [uris] }
|
||||
|
||||
const self = this
|
||||
return new SearchReference({
|
||||
messageId: self.messageId,
|
||||
uri: uris
|
||||
})
|
||||
}
|
||||
|
||||
/// --- Exports
|
||||
|
||||
module.exports = SearchResponse
|
||||
Reference in New Issue
Block a user