First commit
This commit is contained in:
165
node_modules/@ldapjs/dn/lib/utils/parse-string/read-attribute-value.js
generated
vendored
Normal file
165
node_modules/@ldapjs/dn/lib/utils/parse-string/read-attribute-value.js
generated
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
'use strict'
|
||||
|
||||
const readHexString = require('./read-hex-string')
|
||||
const readEscapeSequence = require('./read-escape-sequence')
|
||||
|
||||
/**
|
||||
* @typedef {object} ReadAttributeValueResult
|
||||
* @property {number} endPos The position in the buffer that marks the end of
|
||||
* the value.
|
||||
* @property {string | import('@ldapjs/asn1').BerReader} value
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read an attribute value string from a given {@link Buffer} and return it.
|
||||
* If the value is an encoded octet string, it will be decoded and returned
|
||||
* as a {@link Buffer}.
|
||||
*
|
||||
* @param {Buffer} searchBuffer
|
||||
* @param {number} startPos
|
||||
*
|
||||
* @returns {ReadAttributeValueResult}
|
||||
*
|
||||
* @throws When there is a syntax error in the attribute value string.
|
||||
*/
|
||||
module.exports = function readAttributeValue ({ searchBuffer, startPos }) {
|
||||
let pos = startPos
|
||||
|
||||
while (pos < searchBuffer.byteLength && searchBuffer[pos] === 0x20) {
|
||||
// Skip over any leading whitespace before the '='.
|
||||
pos += 1
|
||||
}
|
||||
|
||||
if (pos >= searchBuffer.byteLength || searchBuffer[pos] !== 0x3d) {
|
||||
throw Error('attribute value does not start with equals sign')
|
||||
}
|
||||
|
||||
// Advance past the equals sign.
|
||||
pos += 1
|
||||
while (pos <= searchBuffer.byteLength && searchBuffer[pos] === 0x20) {
|
||||
// Advance past any leading whitespace.
|
||||
pos += 1
|
||||
}
|
||||
|
||||
if (pos >= searchBuffer.byteLength) {
|
||||
return { endPos: pos, value: '' }
|
||||
}
|
||||
|
||||
if (searchBuffer[pos] === 0x23) {
|
||||
const result = readHexString({ searchBuffer, startPos: pos + 1 })
|
||||
pos = result.endPos
|
||||
return { endPos: pos, value: result.berReader }
|
||||
}
|
||||
|
||||
const readValueResult = readValueString({ searchBuffer, startPos: pos })
|
||||
pos = readValueResult.endPos
|
||||
return {
|
||||
endPos: pos,
|
||||
value: readValueResult.value.toString('utf8').trim()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} ReadValueStringResult
|
||||
* @property {number} endPos
|
||||
* @property {Buffer} value
|
||||
* @private
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read a series of bytes from the buffer as a plain string.
|
||||
*
|
||||
* @param {Buffer} searchBuffer
|
||||
* @param {number} startPos
|
||||
*
|
||||
* @returns {ReadValueStringResult}
|
||||
*
|
||||
* @throws When the attribute value is malformed.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function readValueString ({ searchBuffer, startPos }) {
|
||||
let pos = startPos
|
||||
let inQuotes = false
|
||||
let endQuotePresent = false
|
||||
|
||||
const bytes = []
|
||||
while (pos <= searchBuffer.byteLength) {
|
||||
const char = searchBuffer[pos]
|
||||
|
||||
if (pos === searchBuffer.byteLength) {
|
||||
if (inQuotes === true && endQuotePresent === false) {
|
||||
throw Error('missing ending double quote for attribute value')
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if (char === 0x22) {
|
||||
// Handle the double quote (") character.
|
||||
// RFC 2253 §4 allows for attribute values to be wrapped in double
|
||||
// quotes in order to allow certain characters to be unescaped.
|
||||
// We are not enforcing escaping of characters in this parser, so we only
|
||||
// need to recognize that the quotes are present. Our RDN string encoder
|
||||
// will escape characters as necessary.
|
||||
if (inQuotes === true) {
|
||||
pos += 1
|
||||
endQuotePresent = true
|
||||
|
||||
// We should be at the end of the value.
|
||||
while (pos < searchBuffer.byteLength) {
|
||||
const nextChar = searchBuffer[pos]
|
||||
if (isEndChar(nextChar) === true) {
|
||||
break
|
||||
}
|
||||
if (nextChar !== 0x20) {
|
||||
throw Error('significant rdn character found outside of quotes at position ' + pos)
|
||||
}
|
||||
pos += 1
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if (pos !== startPos) {
|
||||
throw Error('unexpected quote (") in rdn string at position ' + pos)
|
||||
}
|
||||
inQuotes = true
|
||||
pos += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if (isEndChar(char) === true && inQuotes === false) {
|
||||
break
|
||||
}
|
||||
|
||||
if (char === 0x5c) {
|
||||
// We have encountered the start of an escape sequence.
|
||||
const seqResult = readEscapeSequence({
|
||||
searchBuffer,
|
||||
startPos: pos
|
||||
})
|
||||
pos = seqResult.endPos
|
||||
Array.prototype.push.apply(bytes, seqResult.parsed)
|
||||
continue
|
||||
}
|
||||
|
||||
bytes.push(char)
|
||||
pos += 1
|
||||
}
|
||||
|
||||
return {
|
||||
endPos: pos,
|
||||
value: Buffer.from(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
function isEndChar (c) {
|
||||
switch (c) {
|
||||
case 0x2b: // +
|
||||
case 0x2c: // ,
|
||||
case 0x3b: // ; -- Allowed by RFC 2253 §4 in place of a comma.
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user