search_response.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright 2011 Mark Cavage, Inc. All rights reserved.
  2. const assert = require('assert-plus')
  3. const Attribute = require('@ldapjs/attribute')
  4. const {
  5. SearchResultEntry: SearchEntry,
  6. SearchResultReference: SearchReference,
  7. SearchResultDone
  8. } = require('@ldapjs/messages')
  9. const parseDN = require('@ldapjs/dn').DN.fromString
  10. /// --- API
  11. class SearchResponse extends SearchResultDone {
  12. attributes
  13. notAttributes
  14. sentEntries
  15. constructor (options = {}) {
  16. super(options)
  17. this.attributes = options.attributes ? options.attributes.slice() : []
  18. this.notAttributes = []
  19. this.sentEntries = 0
  20. }
  21. }
  22. /**
  23. * Allows you to send a SearchEntry back to the client.
  24. *
  25. * @param {Object} entry an instance of SearchEntry.
  26. * @param {Boolean} nofiltering skip filtering notAttributes and '_' attributes.
  27. * Defaults to 'false'.
  28. */
  29. SearchResponse.prototype.send = function (entry, nofiltering) {
  30. if (!entry || typeof (entry) !== 'object') { throw new TypeError('entry (SearchEntry) required') }
  31. if (nofiltering === undefined) { nofiltering = false }
  32. if (typeof (nofiltering) !== 'boolean') { throw new TypeError('noFiltering must be a boolean') }
  33. const self = this
  34. const savedAttrs = {}
  35. let save = null
  36. if (entry instanceof SearchEntry || entry instanceof SearchReference) {
  37. if (!entry.messageId) { entry.messageId = this.messageId }
  38. if (entry.messageId !== this.messageId) {
  39. throw new Error('SearchEntry messageId mismatch')
  40. }
  41. } else {
  42. if (!entry.attributes) { throw new Error('entry.attributes required') }
  43. const all = (self.attributes.indexOf('*') !== -1)
  44. // Filter attributes in a plain object according to the magic `_` prefix
  45. // and presence in `notAttributes`.
  46. Object.keys(entry.attributes).forEach(function (a) {
  47. const _a = a.toLowerCase()
  48. if (!nofiltering && _a.length && _a[0] === '_') {
  49. savedAttrs[a] = entry.attributes[a]
  50. delete entry.attributes[a]
  51. } else if (!nofiltering && self.notAttributes.indexOf(_a) !== -1) {
  52. savedAttrs[a] = entry.attributes[a]
  53. delete entry.attributes[a]
  54. } else if (all) {
  55. // do nothing
  56. } else if (self.attributes.length && self.attributes.indexOf(_a) === -1) {
  57. savedAttrs[a] = entry.attributes[a]
  58. delete entry.attributes[a]
  59. }
  60. })
  61. save = entry
  62. entry = new SearchEntry({
  63. objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn,
  64. messageId: self.messageId,
  65. attributes: Attribute.fromObject(entry.attributes)
  66. })
  67. }
  68. try {
  69. this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.pojo)
  70. this.connection.write(entry.toBer().buffer)
  71. this.sentEntries++
  72. // Restore attributes
  73. Object.keys(savedAttrs).forEach(function (k) {
  74. save.attributes[k] = savedAttrs[k]
  75. })
  76. } catch (e) {
  77. this.log.warn(e, '%s failure to write message %j',
  78. this.connection.ldap.id, this.pojo)
  79. }
  80. }
  81. SearchResponse.prototype.createSearchEntry = function (object) {
  82. assert.object(object)
  83. const entry = new SearchEntry({
  84. messageId: this.messageId,
  85. objectName: object.objectName || object.dn,
  86. attributes: object.attributes ?? []
  87. })
  88. return entry
  89. }
  90. SearchResponse.prototype.createSearchReference = function (uris) {
  91. if (!uris) { throw new TypeError('uris ([string]) required') }
  92. if (!Array.isArray(uris)) { uris = [uris] }
  93. const self = this
  94. return new SearchReference({
  95. messageId: self.messageId,
  96. uri: uris
  97. })
  98. }
  99. /// --- Exports
  100. module.exports = SearchResponse