'use strict' /** * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com) * All rights reserved. * * This source code is licensed under the MIT license found in the * README.md file in the root directory of this source tree. */ const crypto = require('crypto') const defaults = require('./defaults') function escapeElement(elementRepresentation) { var escaped = elementRepresentation.replace(/\\/g, '\\\\').replace(/"/g, '\\"') return '"' + escaped + '"' } // convert a JS array to a postgres array literal // uses comma separator so won't work for types like box that use // a different array separator. function arrayString(val) { var result = '{' for (var i = 0; i < val.length; i++) { if (i > 0) { result = result + ',' } if (val[i] === null || typeof val[i] === 'undefined') { result = result + 'NULL' } else if (Array.isArray(val[i])) { result = result + arrayString(val[i]) } else if (val[i] instanceof Buffer) { result += '\\\\x' + val[i].toString('hex') } else { result += escapeElement(prepareValue(val[i])) } } result = result + '}' return result } // converts values from javascript types // to their 'raw' counterparts for use as a postgres parameter // note: you can override this function to provide your own conversion mechanism // for complex types, etc... var prepareValue = function (val, seen) { if (val instanceof Buffer) { return val } if (ArrayBuffer.isView(val)) { var buf = Buffer.from(val.buffer, val.byteOffset, val.byteLength) if (buf.length === val.byteLength) { return buf } return buf.slice(val.byteOffset, val.byteOffset + val.byteLength) // Node.js v4 does not support those Buffer.from params } if (val instanceof Date) { if (defaults.parseInputDatesAsUTC) { return dateToStringUTC(val) } else { return dateToString(val) } } if (Array.isArray(val)) { return arrayString(val) } if (val === null || typeof val === 'undefined') { return null } if (typeof val === 'object') { return prepareObject(val, seen) } return val.toString() } function prepareObject(val, seen) { if (val && typeof val.toPostgres === 'function') { seen = seen || [] if (seen.indexOf(val) !== -1) { throw new Error('circular reference detected while preparing "' + val + '" for query') } seen.push(val) return prepareValue(val.toPostgres(prepareValue), seen) } return JSON.stringify(val) } function pad(number, digits) { number = '' + number while (number.length < digits) { number = '0' + number } return number } function dateToString(date) { var offset = -date.getTimezoneOffset() var year = date.getFullYear() var isBCYear = year < 1 if (isBCYear) year = Math.abs(year) + 1 // negative years are 1 off their BC representation var ret = pad(year, 4) + '-' + pad(date.getMonth() + 1, 2) + '-' + pad(date.getDate(), 2) + 'T' + pad(date.getHours(), 2) + ':' + pad(date.getMinutes(), 2) + ':' + pad(date.getSeconds(), 2) + '.' + pad(date.getMilliseconds(), 3) if (offset < 0) { ret += '-' offset *= -1 } else { ret += '+' } ret += pad(Math.floor(offset / 60), 2) + ':' + pad(offset % 60, 2) if (isBCYear) ret += ' BC' return ret } function dateToStringUTC(date) { var year = date.getUTCFullYear() var isBCYear = year < 1 if (isBCYear) year = Math.abs(year) + 1 // negative years are 1 off their BC representation var ret = pad(year, 4) + '-' + pad(date.getUTCMonth() + 1, 2) + '-' + pad(date.getUTCDate(), 2) + 'T' + pad(date.getUTCHours(), 2) + ':' + pad(date.getUTCMinutes(), 2) + ':' + pad(date.getUTCSeconds(), 2) + '.' + pad(date.getUTCMilliseconds(), 3) ret += '+00:00' if (isBCYear) ret += ' BC' return ret } function normalizeQueryConfig(config, values, callback) { // can take in strings or config objects config = typeof config === 'string' ? { text: config } : config if (values) { if (typeof values === 'function') { config.callback = values } else { config.values = values } } if (callback) { config.callback = callback } return config } const md5 = function (string) { return crypto.createHash('md5').update(string, 'utf-8').digest('hex') } // See AuthenticationMD5Password at https://www.postgresql.org/docs/current/static/protocol-flow.html const postgresMd5PasswordHash = function (user, password, salt) { var inner = md5(password + user) var outer = md5(Buffer.concat([Buffer.from(inner), salt])) return 'md5' + outer } module.exports = { prepareValue: function prepareValueWrapper(value) { // this ensures that extra arguments do not get passed into prepareValue // by accident, eg: from calling values.map(utils.prepareValue) return prepareValue(value) }, normalizeQueryConfig, postgresMd5PasswordHash, md5, }