1 |
|
2 |
|
3 | const assert = require('assert-plus')
|
4 | const util = require('util')
|
5 |
|
6 | const LDAPResult = require('./result')
|
7 | const SearchEntry = require('./search_entry')
|
8 | const SearchReference = require('./search_reference')
|
9 |
|
10 | const dtrace = require('../dtrace')
|
11 | const parseDN = require('../dn').parse
|
12 | const parseURL = require('../url').parse
|
13 | const Protocol = require('../protocol')
|
14 |
|
15 |
|
16 |
|
17 | function SearchResponse (options) {
|
18 | options = options || {}
|
19 | assert.object(options)
|
20 |
|
21 | options.protocolOp = Protocol.LDAP_REP_SEARCH
|
22 | LDAPResult.call(this, options)
|
23 |
|
24 | this.attributes = options.attributes ? options.attributes.slice() : []
|
25 | this.notAttributes = []
|
26 | this.sentEntries = 0
|
27 | }
|
28 | util.inherits(SearchResponse, LDAPResult)
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | SearchResponse.prototype.send = function (entry, nofiltering) {
|
38 | if (!entry || typeof (entry) !== 'object') { throw new TypeError('entry (SearchEntry) required') }
|
39 | if (nofiltering === undefined) { nofiltering = false }
|
40 | if (typeof (nofiltering) !== 'boolean') { throw new TypeError('noFiltering must be a boolean') }
|
41 |
|
42 | const self = this
|
43 |
|
44 | const savedAttrs = {}
|
45 | let save = null
|
46 | if (entry instanceof SearchEntry || entry instanceof SearchReference) {
|
47 | if (!entry.messageID) { entry.messageID = this.messageID }
|
48 | if (entry.messageID !== this.messageID) { throw new Error('SearchEntry messageID mismatch') }
|
49 | } else {
|
50 | if (!entry.attributes) { throw new Error('entry.attributes required') }
|
51 |
|
52 | const all = (self.attributes.indexOf('*') !== -1)
|
53 | Object.keys(entry.attributes).forEach(function (a) {
|
54 | const _a = a.toLowerCase()
|
55 | if (!nofiltering && _a.length && _a[0] === '_') {
|
56 | savedAttrs[a] = entry.attributes[a]
|
57 | delete entry.attributes[a]
|
58 | } else if (!nofiltering && self.notAttributes.indexOf(_a) !== -1) {
|
59 | savedAttrs[a] = entry.attributes[a]
|
60 | delete entry.attributes[a]
|
61 | } else if (all) {
|
62 |
|
63 | } else if (self.attributes.length && self.attributes.indexOf(_a) === -1) {
|
64 | savedAttrs[a] = entry.attributes[a]
|
65 | delete entry.attributes[a]
|
66 | }
|
67 | })
|
68 |
|
69 | save = entry
|
70 | entry = new SearchEntry({
|
71 | objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn,
|
72 | messageID: self.messageID,
|
73 | log: self.log
|
74 | })
|
75 | entry.fromObject(save)
|
76 | }
|
77 |
|
78 | try {
|
79 | this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.json)
|
80 |
|
81 | this.connection.write(entry.toBer())
|
82 | this.sentEntries++
|
83 |
|
84 | if (self._dtraceOp && self._dtraceId) {
|
85 | dtrace.fire('server-search-entry', function () {
|
86 | const c = self.connection || { ldap: {} }
|
87 | return [
|
88 | self._dtraceId || 0,
|
89 | (c.remoteAddress || ''),
|
90 | c.ldap.bindDN ? c.ldap.bindDN.toString() : '',
|
91 | (self.requestDN ? self.requestDN.toString() : ''),
|
92 | entry.objectName.toString(),
|
93 | entry.attributes.length
|
94 | ]
|
95 | })
|
96 | }
|
97 |
|
98 |
|
99 | Object.keys(savedAttrs).forEach(function (k) {
|
100 | save.attributes[k] = savedAttrs[k]
|
101 | })
|
102 | } catch (e) {
|
103 | this.log.warn(e, '%s failure to write message %j',
|
104 | this.connection.ldap.id, this.json)
|
105 | }
|
106 | }
|
107 |
|
108 | SearchResponse.prototype.createSearchEntry = function (object) {
|
109 | assert.object(object)
|
110 |
|
111 | const entry = new SearchEntry({
|
112 | messageID: this.messageID,
|
113 | log: this.log,
|
114 | objectName: object.objectName || object.dn
|
115 | })
|
116 | entry.fromObject((object.attributes || object))
|
117 | return entry
|
118 | }
|
119 |
|
120 | SearchResponse.prototype.createSearchReference = function (uris) {
|
121 | if (!uris) { throw new TypeError('uris ([string]) required') }
|
122 |
|
123 | if (!Array.isArray(uris)) { uris = [uris] }
|
124 |
|
125 | for (let i = 0; i < uris.length; i++) {
|
126 | if (typeof (uris[i]) === 'string') { uris[i] = parseURL(uris[i]) }
|
127 | }
|
128 |
|
129 | const self = this
|
130 | return new SearchReference({
|
131 | messageID: self.messageID,
|
132 | log: self.log,
|
133 | uris: uris
|
134 | })
|
135 | }
|
136 |
|
137 |
|
138 |
|
139 | module.exports = SearchResponse
|