node-ldapjs/lib/messages/parser.js

222 lines
5.1 KiB
JavaScript

// 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('asn1')
// var VError = require('verror').VError
const logger = require('../logger')
const AbandonRequest = require('./abandon_request')
const AddRequest = require('./add_request')
const AddResponse = require('./add_response')
const BindRequest = require('./bind_request')
const BindResponse = require('./bind_response')
const CompareRequest = require('./compare_request')
const CompareResponse = require('./compare_response')
const DeleteRequest = require('./del_request')
const DeleteResponse = require('./del_response')
const ExtendedRequest = require('./ext_request')
const ExtendedResponse = require('./ext_response')
const ModifyRequest = require('./modify_request')
const ModifyResponse = require('./modify_response')
const ModifyDNRequest = require('./moddn_request')
const ModifyDNResponse = require('./moddn_response')
const SearchRequest = require('./search_request')
const SearchEntry = require('./search_entry')
const SearchReference = require('./search_reference')
const SearchResponse = require('./search_response')
const UnbindRequest = require('./unbind_request')
// var UnbindResponse = require('./unbind_response')
const LDAPResult = require('./result')
// var Message = require('./message')
const Protocol = require('../protocol')
/// --- Globals
// var Ber = asn1.Ber
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)
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)
const 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 sort of ugly, but allows us to make miminal copies
nextMessage = self.buffer.slice(ber.offset + ber.length)
ber._size = ber.offset + ber.length
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 {
// Bail here if peer isn't speaking protocol at all
message = this.getMessage(ber)
if (!message) {
return end()
}
message.parse(ber)
} 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.LDAP_REQ_ABANDON:
Message = AbandonRequest
break
case Protocol.LDAP_REQ_ADD:
Message = AddRequest
break
case Protocol.LDAP_REP_ADD:
Message = AddResponse
break
case Protocol.LDAP_REQ_BIND:
Message = BindRequest
break
case Protocol.LDAP_REP_BIND:
Message = BindResponse
break
case Protocol.LDAP_REQ_COMPARE:
Message = CompareRequest
break
case Protocol.LDAP_REP_COMPARE:
Message = CompareResponse
break
case Protocol.LDAP_REQ_DELETE:
Message = DeleteRequest
break
case Protocol.LDAP_REP_DELETE:
Message = DeleteResponse
break
case Protocol.LDAP_REQ_EXTENSION:
Message = ExtendedRequest
break
case Protocol.LDAP_REP_EXTENSION:
Message = ExtendedResponse
break
case Protocol.LDAP_REQ_MODIFY:
Message = ModifyRequest
break
case Protocol.LDAP_REP_MODIFY:
Message = ModifyResponse
break
case Protocol.LDAP_REQ_MODRDN:
Message = ModifyDNRequest
break
case Protocol.LDAP_REP_MODRDN:
Message = ModifyDNResponse
break
case Protocol.LDAP_REQ_SEARCH:
Message = SearchRequest
break
case Protocol.LDAP_REP_SEARCH_ENTRY:
Message = SearchEntry
break
case Protocol.LDAP_REP_SEARCH_REF:
Message = SearchReference
break
case Protocol.LDAP_REP_SEARCH:
Message = SearchResponse
break
case Protocol.LDAP_REQ_UNBIND:
Message = UnbindRequest
break
default:
this.emit('error',
new Error('Op 0x' + (type ? type.toString(16) : '??') +
' not supported'),
new LDAPResult({
messageID: messageID,
protocolOp: type || Protocol.LDAP_REP_EXTENSION
}))
return false
}
return new Message({
messageID: messageID,
log: self.log
})
}
/// --- Exports
module.exports = Parser