sql-string-escape
Version:
Simple SQL string escape.
69 lines (60 loc) • 2.38 kB
JavaScript
// eslint-disable-next-line no-control-regex
const CHARS_GLOBAL_BACKSLASH_SUPPORTED_RX = /[\0\b\t\n\r\x1a"'\\]/g
const CHARS_ESCAPE_BACKSLASH_SUPPORTED_MAP = {
'\0' : '\\0'
, '\b' : '\\b'
, '\t' : '\\t'
, '\n' : '\\n'
, '\r' : '\\r'
, '\x1a' : '\\Z'
, '"' : '\\"'
, '\'' : '\\\''
, '\\' : '\\\\'
}
/**
* Escapes the given string to protect against SQL injection attacks.
*
* By default it assumes that backslashes are not supported as they are not part of the standard SQL spec.
* Quoting from the [SQLlite web site](https://sqlite.org/lang_expr.html):
*
* > C-style escapes using the backslash character are not supported because they are not standard SQL.
*
* This means three things:
*
* - backslashes and double quotes `"` are not escaped by default
* - single quotes are escaped via `''` instead of `\'`
* - your sql engine should throw an error when encountering a backslash escape
* as part of a string, unless it is a literal backslash, i.e. `'backslash: \\'`.
*
* It is recommended to set the `backslashSupported` option `true` if your SQL
* engine supports it. In that case backslash sequences are escaped and single
* and double quotes are escaped via a backslash, i.e. `'\''`.
*
* @param {String} val the original string to be used in a SQL query
* @param {Object} $0 opts
* @param {Boolean} [$0.backslashSupported = false] if `true` backslashes are supported
* @returns {String} the original string escaped wrapped in single quotes, i.e. `'mystring'`
*/
function escapeString(val, opts) {
if (val == null) {
throw new Error('Need to pass a valid string')
}
opts = opts || {}
const backslashSupported = !!opts.backslashSupported
if (!backslashSupported) return "'" + val.replace(/'/g, "''") + "'"
const charsRx = CHARS_GLOBAL_BACKSLASH_SUPPORTED_RX
const charsEscapeMap = CHARS_ESCAPE_BACKSLASH_SUPPORTED_MAP
var chunkIndex = charsRx.lastIndex = 0
var escapedVal = ''
var match
while ((match = charsRx.exec(val))) {
escapedVal += val.slice(chunkIndex, match.index) + charsEscapeMap[match[0]]
chunkIndex = charsRx.lastIndex
}
// Nothing was escaped
if (chunkIndex === 0) return "'" + val + "'"
if (chunkIndex < val.length) return "'" + escapedVal + val.slice(chunkIndex) + "'"
return "'" + escapedVal + "'"
}
module.exports = escapeString