2011-08-04 20:32:01 +00:00
|
|
|
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const assert = require('assert-plus')
|
|
|
|
const util = require('util')
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const LDAPResult = require('./result')
|
|
|
|
const SearchEntry = require('./search_entry')
|
|
|
|
const SearchReference = require('./search_reference')
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const dtrace = require('../dtrace')
|
|
|
|
const parseDN = require('../dn').parse
|
|
|
|
const parseURL = require('../url').parse
|
|
|
|
const Protocol = require('../protocol')
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
/// --- API
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
function SearchResponse (options) {
|
|
|
|
options = options || {}
|
|
|
|
assert.object(options)
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
options.protocolOp = Protocol.LDAP_REP_SEARCH
|
|
|
|
LDAPResult.call(this, options)
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
this.attributes = options.attributes ? options.attributes.slice() : []
|
|
|
|
this.notAttributes = []
|
|
|
|
this.sentEntries = 0
|
2011-08-04 20:32:01 +00:00
|
|
|
}
|
2019-08-27 21:11:49 +00:00
|
|
|
util.inherits(SearchResponse, LDAPResult)
|
2011-08-04 20:32:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Allows you to send a SearchEntry back to the client.
|
|
|
|
*
|
|
|
|
* @param {Object} entry an instance of SearchEntry.
|
2011-09-16 16:06:35 +00:00
|
|
|
* @param {Boolean} nofiltering skip filtering notAttributes and '_' attributes.
|
|
|
|
* Defaults to 'false'.
|
2011-08-04 20:32:01 +00:00
|
|
|
*/
|
2012-02-18 08:15:52 +00:00
|
|
|
SearchResponse.prototype.send = function (entry, nofiltering) {
|
2019-08-27 21:11:49 +00:00
|
|
|
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') }
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const self = this
|
2011-08-12 23:37:47 +00:00
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const savedAttrs = {}
|
2020-12-02 22:44:31 +00:00
|
|
|
let save = null
|
2011-09-27 18:49:33 +00:00
|
|
|
if (entry instanceof SearchEntry || entry instanceof SearchReference) {
|
2019-08-27 21:11:49 +00:00
|
|
|
if (!entry.messageID) { entry.messageID = this.messageID }
|
|
|
|
if (entry.messageID !== this.messageID) { throw new Error('SearchEntry messageID mismatch') }
|
2011-09-27 18:49:33 +00:00
|
|
|
} else {
|
2019-08-27 21:11:49 +00:00
|
|
|
if (!entry.attributes) { throw new Error('entry.attributes required') }
|
2011-08-12 23:37:47 +00:00
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const all = (self.attributes.indexOf('*') !== -1)
|
2012-02-18 08:15:52 +00:00
|
|
|
Object.keys(entry.attributes).forEach(function (a) {
|
2020-10-31 21:07:32 +00:00
|
|
|
const _a = a.toLowerCase()
|
2011-10-17 23:37:09 +00:00
|
|
|
if (!nofiltering && _a.length && _a[0] === '_') {
|
2019-08-27 21:11:49 +00:00
|
|
|
savedAttrs[a] = entry.attributes[a]
|
|
|
|
delete entry.attributes[a]
|
2011-10-18 19:31:52 +00:00
|
|
|
} else if (!nofiltering && self.notAttributes.indexOf(_a) !== -1) {
|
2019-08-27 21:11:49 +00:00
|
|
|
savedAttrs[a] = entry.attributes[a]
|
|
|
|
delete entry.attributes[a]
|
2011-10-17 23:37:09 +00:00
|
|
|
} else if (all) {
|
2020-10-31 21:07:32 +00:00
|
|
|
// do nothing
|
2011-10-17 23:37:09 +00:00
|
|
|
} else if (self.attributes.length && self.attributes.indexOf(_a) === -1) {
|
2019-08-27 21:11:49 +00:00
|
|
|
savedAttrs[a] = entry.attributes[a]
|
|
|
|
delete entry.attributes[a]
|
2011-10-17 23:37:09 +00:00
|
|
|
}
|
2019-08-27 21:11:49 +00:00
|
|
|
})
|
2011-10-11 17:43:27 +00:00
|
|
|
|
2020-12-02 22:44:31 +00:00
|
|
|
save = entry
|
2011-08-12 23:37:47 +00:00
|
|
|
entry = new SearchEntry({
|
2012-02-18 08:15:52 +00:00
|
|
|
objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn,
|
2011-08-12 23:37:47 +00:00
|
|
|
messageID: self.messageID,
|
2012-02-18 08:54:22 +00:00
|
|
|
log: self.log
|
2019-08-27 21:11:49 +00:00
|
|
|
})
|
|
|
|
entry.fromObject(save)
|
2011-08-12 23:37:47 +00:00
|
|
|
}
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2011-08-12 23:37:47 +00:00
|
|
|
try {
|
2020-11-12 17:38:56 +00:00
|
|
|
this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.json)
|
2011-08-12 23:37:47 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
this.connection.write(entry.toBer())
|
|
|
|
this.sentEntries++
|
2011-11-15 18:49:23 +00:00
|
|
|
|
|
|
|
if (self._dtraceOp && self._dtraceId) {
|
2012-02-18 08:15:52 +00:00
|
|
|
dtrace.fire('server-search-entry', function () {
|
2020-10-31 21:07:32 +00:00
|
|
|
const c = self.connection || { ldap: {} }
|
2011-11-15 18:49:23 +00:00
|
|
|
return [
|
|
|
|
self._dtraceId || 0,
|
|
|
|
(c.remoteAddress || ''),
|
|
|
|
c.ldap.bindDN ? c.ldap.bindDN.toString() : '',
|
|
|
|
(self.requestDN ? self.requestDN.toString() : ''),
|
|
|
|
entry.objectName.toString(),
|
2011-11-22 21:29:19 +00:00
|
|
|
entry.attributes.length
|
2019-08-27 21:11:49 +00:00
|
|
|
]
|
|
|
|
})
|
2011-11-15 18:49:23 +00:00
|
|
|
}
|
2011-11-22 21:29:19 +00:00
|
|
|
|
|
|
|
// Restore attributes
|
2020-10-31 21:07:32 +00:00
|
|
|
Object.keys(savedAttrs).forEach(function (k) {
|
2019-08-27 21:11:49 +00:00
|
|
|
save.attributes[k] = savedAttrs[k]
|
|
|
|
})
|
2011-08-12 23:37:47 +00:00
|
|
|
} catch (e) {
|
2012-07-09 13:00:51 +00:00
|
|
|
this.log.warn(e, '%s failure to write message %j',
|
2019-08-27 21:11:49 +00:00
|
|
|
this.connection.ldap.id, this.json)
|
2011-08-12 23:37:47 +00:00
|
|
|
}
|
2019-08-27 21:11:49 +00:00
|
|
|
}
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2012-02-18 08:15:52 +00:00
|
|
|
SearchResponse.prototype.createSearchEntry = function (object) {
|
2019-08-27 21:11:49 +00:00
|
|
|
assert.object(object)
|
2011-08-04 20:32:01 +00:00
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const entry = new SearchEntry({
|
2015-10-31 17:28:25 +00:00
|
|
|
messageID: this.messageID,
|
|
|
|
log: this.log,
|
2011-08-12 23:37:47 +00:00
|
|
|
objectName: object.objectName || object.dn
|
2019-08-27 21:11:49 +00:00
|
|
|
})
|
|
|
|
entry.fromObject((object.attributes || object))
|
|
|
|
return entry
|
|
|
|
}
|
2011-09-27 18:49:33 +00:00
|
|
|
|
2012-02-18 08:15:52 +00:00
|
|
|
SearchResponse.prototype.createSearchReference = function (uris) {
|
2019-08-27 21:11:49 +00:00
|
|
|
if (!uris) { throw new TypeError('uris ([string]) required') }
|
2011-09-27 18:49:33 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
if (!Array.isArray(uris)) { uris = [uris] }
|
2011-09-27 18:49:33 +00:00
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
for (let i = 0; i < uris.length; i++) {
|
2019-08-27 21:11:49 +00:00
|
|
|
if (typeof (uris[i]) === 'string') { uris[i] = parseURL(uris[i]) }
|
2011-09-27 18:49:33 +00:00
|
|
|
}
|
|
|
|
|
2020-10-31 21:07:32 +00:00
|
|
|
const self = this
|
2011-09-27 18:49:33 +00:00
|
|
|
return new SearchReference({
|
|
|
|
messageID: self.messageID,
|
2012-02-18 08:54:22 +00:00
|
|
|
log: self.log,
|
2011-09-27 18:49:33 +00:00
|
|
|
uris: uris
|
2019-08-27 21:11:49 +00:00
|
|
|
})
|
|
|
|
}
|
2015-10-31 17:28:25 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
/// --- Exports
|
2015-10-31 17:28:25 +00:00
|
|
|
|
2019-08-27 21:11:49 +00:00
|
|
|
module.exports = SearchResponse
|