parse-to-message.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. 'use strict'
  2. const { operations } = require('@ldapjs/protocol')
  3. const { getControl } = require('@ldapjs/controls')
  4. const messageClasses = {
  5. AbandonRequest: require('./messages/abandon-request'),
  6. AddRequest: require('./messages/add-request'),
  7. BindRequest: require('./messages/bind-request'),
  8. CompareRequest: require('./messages/compare-request'),
  9. DeleteRequest: require('./messages/delete-request'),
  10. ExtensionRequest: require('./messages/extension-request'),
  11. ModifyRequest: require('./messages/modify-request'),
  12. ModifyDnRequest: require('./messages/modifydn-request'),
  13. SearchRequest: require('./messages/search-request'),
  14. UnbindRequest: require('./messages/unbind-request'),
  15. AbandonResponse: require('./messages/abandon-response'),
  16. AddResponse: require('./messages/add-response'),
  17. BindResponse: require('./messages/bind-response'),
  18. CompareResponse: require('./messages/compare-response'),
  19. DeleteResponse: require('./messages/delete-response'),
  20. ExtensionResponse: require('./messages/extension-response'),
  21. ModifyResponse: require('./messages/modify-response'),
  22. ModifyDnResponse: require('./messages/modifydn-response'),
  23. // Search result messages.
  24. SearchResultEntry: require('./messages/search-result-entry'),
  25. SearchResultReference: require('./messages/search-result-reference'),
  26. SearchResultDone: require('./messages/search-result-done'),
  27. // Miscellaneous messages.
  28. IntermediateResponse: require('./messages/intermediate-response')
  29. }
  30. /**
  31. * Utility function that inspects a BER object and parses it into an instance
  32. * of a specific LDAP message.
  33. *
  34. * @param {import('@ldapjs/asn1').BerReader} ber An object that represents a
  35. * full LDAP Message sequence as described in
  36. * https://www.rfc-editor.org/rfc/rfc4511.html#section-4.1.1.
  37. *
  38. * @returns {LdapMessage} Some specific instance of the base LDAP Message
  39. * type.
  40. *
  41. * @throws When the input data is malformed.
  42. */
  43. module.exports = function parseToMessage (ber) {
  44. const inputType = Object.prototype.toString.apply(ber)
  45. if (inputType !== '[object BerReader]') {
  46. throw TypeError(`Expected BerReader but got ${inputType}.`)
  47. }
  48. ber.readSequence()
  49. const messageId = ber.readInt()
  50. const messageType = identifyType(ber)
  51. const MessageClass = messageClasses[messageType]
  52. const pojoMessage = MessageClass.parseToPojo(ber)
  53. const message = new MessageClass({
  54. messageId,
  55. ...pojoMessage
  56. })
  57. // Look for controls
  58. if (ber.peek() === 0xa0) {
  59. ber.readSequence()
  60. const end = ber.offset + ber.length
  61. while (ber.offset < end) {
  62. const c = getControl(ber)
  63. /* istanbul ignore else */
  64. if (c) {
  65. message.addControl(c)
  66. }
  67. }
  68. }
  69. return message
  70. }
  71. /**
  72. * Determines the type of LDAP message the BER represents, e.g. a "Bind Request"
  73. * message.
  74. *
  75. * @param {BerReader} ber
  76. *
  77. * @returns {string}
  78. */
  79. function identifyType (ber) {
  80. let result
  81. switch (ber.peek()) {
  82. case operations.LDAP_REQ_ABANDON: {
  83. result = 'AbandonRequest'
  84. break
  85. }
  86. case 0x00: {
  87. result = 'AbandonResponse'
  88. break
  89. }
  90. case operations.LDAP_REQ_ADD: {
  91. result = 'AddRequest'
  92. break
  93. }
  94. case operations.LDAP_RES_ADD: {
  95. result = 'AddResponse'
  96. break
  97. }
  98. case operations.LDAP_REQ_BIND: {
  99. result = 'BindRequest'
  100. break
  101. }
  102. case operations.LDAP_RES_BIND: {
  103. result = 'BindResponse'
  104. break
  105. }
  106. case operations.LDAP_REQ_COMPARE: {
  107. result = 'CompareRequest'
  108. break
  109. }
  110. case operations.LDAP_RES_COMPARE: {
  111. result = 'CompareResponse'
  112. break
  113. }
  114. case operations.LDAP_REQ_DELETE: {
  115. result = 'DeleteRequest'
  116. break
  117. }
  118. case operations.LDAP_RES_DELETE: {
  119. result = 'DeleteResponse'
  120. break
  121. }
  122. case operations.LDAP_REQ_EXTENSION: {
  123. result = 'ExtensionRequest'
  124. break
  125. }
  126. case operations.LDAP_RES_EXTENSION: {
  127. result = 'ExtensionResponse'
  128. break
  129. }
  130. case operations.LDAP_REQ_MODIFY: {
  131. result = 'ModifyRequest'
  132. break
  133. }
  134. case operations.LDAP_RES_MODIFY: {
  135. result = 'ModifyResponse'
  136. break
  137. }
  138. case operations.LDAP_REQ_MODRDN: {
  139. result = 'ModifyDnRequest'
  140. break
  141. }
  142. case operations.LDAP_RES_MODRDN: {
  143. result = 'ModifyDnResponse'
  144. break
  145. }
  146. case operations.LDAP_REQ_SEARCH: {
  147. result = 'SearchRequest'
  148. break
  149. }
  150. case operations.LDAP_RES_SEARCH_ENTRY: {
  151. result = 'SearchResultEntry'
  152. break
  153. }
  154. case operations.LDAP_RES_SEARCH_REF: {
  155. result = 'SearchResultReference'
  156. break
  157. }
  158. case operations.LDAP_RES_SEARCH_DONE: {
  159. result = 'SearchResultDone'
  160. break
  161. }
  162. case operations.LDAP_REQ_UNBIND: {
  163. result = 'UnbindRequest'
  164. break
  165. }
  166. case operations.LDAP_RES_INTERMEDIATE: {
  167. result = 'IntermediateResponse'
  168. break
  169. }
  170. }
  171. return result
  172. }