diff options
Diffstat (limited to 'node_modules/sqlstring')
| -rw-r--r-- | node_modules/sqlstring/HISTORY.md | 48 | ||||
| -rw-r--r-- | node_modules/sqlstring/LICENSE | 19 | ||||
| -rw-r--r-- | node_modules/sqlstring/README.md | 232 | ||||
| -rw-r--r-- | node_modules/sqlstring/index.js | 1 | ||||
| -rw-r--r-- | node_modules/sqlstring/lib/SqlString.js | 237 | ||||
| -rw-r--r-- | node_modules/sqlstring/package.json | 47 | 
6 files changed, 584 insertions, 0 deletions
diff --git a/node_modules/sqlstring/HISTORY.md b/node_modules/sqlstring/HISTORY.md new file mode 100644 index 0000000..e5afa0c --- /dev/null +++ b/node_modules/sqlstring/HISTORY.md @@ -0,0 +1,48 @@ +2.3.2 / 2020-04-15 +================== + +  * perf: remove outdated array pattern + +2.3.1 / 2018-02-24 +================== + +  * Fix incorrectly replacing non-placeholders in SQL + +2.3.0 / 2017-10-01 +================== + +  * Add `.toSqlString()` escape overriding +  * Add `raw` method to wrap raw strings for escape overriding +  * Small performance improvement on `escapeId` + +2.2.0 / 2016-11-01 +================== + +  * Escape invalid `Date` objects as `NULL` + +2.1.0 / 2016-09-26 +================== + +  * Accept numbers and other value types in `escapeId` +  * Run `buffer.toString()` through escaping + +2.0.1 / 2016-06-06 +================== + +  * Fix npm package to include missing `lib/` directory + +2.0.0 / 2016-06-06 +================== + +  * Bring repository up-to-date with `mysql` module changes +  * Support Node.js 0.6.x + +1.0.0 / 2014-11-09 +================== + +  * Support Node.js 0.8.x + +0.0.1 / 2014-02-25 +================== + +  * Initial release diff --git a/node_modules/sqlstring/LICENSE b/node_modules/sqlstring/LICENSE new file mode 100644 index 0000000..c7ff12a --- /dev/null +++ b/node_modules/sqlstring/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/node_modules/sqlstring/README.md b/node_modules/sqlstring/README.md new file mode 100644 index 0000000..bdde7a9 --- /dev/null +++ b/node_modules/sqlstring/README.md @@ -0,0 +1,232 @@ +# sqlstring + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![Node.js Version][node-image]][node-url] +[![Build Status][travis-image]][travis-url] +[![Coverage Status][coveralls-image]][coveralls-url] + +Simple SQL escape and format for MySQL + +## Install + +```sh +$ npm install sqlstring +``` + +## Usage + +<!-- eslint-disable no-undef, no-unused-vars --> + +```js +var SqlString = require('sqlstring'); +``` + +### Escaping query values + +**Caution** These methods of escaping values only works when the +[NO_BACKSLASH_ESCAPES](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_backslash_escapes) +SQL mode is disabled (which is the default state for MySQL servers). + +In order to avoid SQL Injection attacks, you should always escape any user +provided data before using it inside a SQL query. You can do so using the +`SqlString.escape()` method: + +<!-- eslint-disable no-undef --> + +```js +var userId = 'some user provided value'; +var sql    = 'SELECT * FROM users WHERE id = ' + SqlString.escape(userId); +console.log(sql); // SELECT * FROM users WHERE id = 'some user provided value' +``` + +Alternatively, you can use `?` characters as placeholders for values you would +like to have escaped like this: + +<!-- eslint-disable no-undef --> + +```js +var userId = 1; +var sql    = SqlString.format('SELECT * FROM users WHERE id = ?', [userId]); +console.log(sql); // SELECT * FROM users WHERE id = 1 +``` + +Multiple placeholders are mapped to values in the same order as passed. For example, +in the following query `foo` equals `a`, `bar` equals `b`, `baz` equals `c`, and +`id` will be `userId`: + +<!-- eslint-disable no-undef --> + +```js +var userId = 1; +var sql    = SqlString.format('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?', +  ['a', 'b', 'c', userId]); +console.log(sql); // UPDATE users SET foo = 'a', bar = 'b', baz = 'c' WHERE id = 1 +``` + +This looks similar to prepared statements in MySQL, however it really just uses +the same `SqlString.escape()` method internally. + +**Caution** This also differs from prepared statements in that all `?` are +replaced, even those contained in comments and strings. + +Different value types are escaped differently, here is how: + +* Numbers are left untouched +* Booleans are converted to `true` / `false` +* Date objects are converted to `'YYYY-mm-dd HH:ii:ss'` strings +* Buffers are converted to hex strings, e.g. `X'0fa5'` +* Strings are safely escaped +* Arrays are turned into list, e.g. `['a', 'b']` turns into `'a', 'b'` +* Nested arrays are turned into grouped lists (for bulk inserts), e.g. `[['a', +  'b'], ['c', 'd']]` turns into `('a', 'b'), ('c', 'd')` +* Objects that have a `toSqlString` method will have `.toSqlString()` called +  and the returned value is used as the raw SQL. +* Objects are turned into `key = 'val'` pairs for each enumerable property on +  the object. If the property's value is a function, it is skipped; if the +  property's value is an object, toString() is called on it and the returned +  value is used. +* `undefined` / `null` are converted to `NULL` +* `NaN` / `Infinity` are left as-is. MySQL does not support these, and trying +  to insert them as values will trigger MySQL errors until they implement +  support. + +You may have noticed that this escaping allows you to do neat things like this: + +<!-- eslint-disable no-undef --> + +```js +var post  = {id: 1, title: 'Hello MySQL'}; +var sql = SqlString.format('INSERT INTO posts SET ?', post); +console.log(sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL' +``` + +And the `toSqlString` method allows you to form complex queries with functions: + +<!-- eslint-disable no-undef --> + +```js +var CURRENT_TIMESTAMP = { toSqlString: function() { return 'CURRENT_TIMESTAMP()'; } }; +var sql = SqlString.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]); +console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42 +``` + +To generate objects with a `toSqlString` method, the `SqlString.raw()` method can +be used. This creates an object that will be left un-touched when using in a `?` +placeholder, useful for using functions as dynamic values: + +**Caution** The string provided to `SqlString.raw()` will skip all escaping +functions when used, so be careful when passing in unvalidated input. + +<!-- eslint-disable no-undef --> + +```js +var CURRENT_TIMESTAMP = SqlString.raw('CURRENT_TIMESTAMP()'); +var sql = SqlString.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]); +console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42 +``` + +If you feel the need to escape queries by yourself, you can also use the escaping +function directly: + +<!-- eslint-disable no-undef --> + +```js +var sql = 'SELECT * FROM posts WHERE title=' + SqlString.escape('Hello MySQL'); +console.log(sql); // SELECT * FROM posts WHERE title='Hello MySQL' +``` + +### Escaping query identifiers + +If you can't trust an SQL identifier (database / table / column name) because it is +provided by a user, you should escape it with `SqlString.escapeId(identifier)` like this: + +<!-- eslint-disable no-undef --> + +```js +var sorter = 'date'; +var sql    = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId(sorter); +console.log(sql); // SELECT * FROM posts ORDER BY `date` +``` + +It also supports adding qualified identifiers. It will escape both parts. + +<!-- eslint-disable no-undef --> + +```js +var sorter = 'date'; +var sql    = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId('posts.' + sorter); +console.log(sql); // SELECT * FROM posts ORDER BY `posts`.`date` +``` + +If you do not want to treat `.` as qualified identifiers, you can set the second +argument to `true` in order to keep the string as a literal identifier: + +<!-- eslint-disable no-undef --> + +```js +var sorter = 'date.2'; +var sql    = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId(sorter, true); +console.log(sql); // SELECT * FROM posts ORDER BY `date.2` +``` + +Alternatively, you can use `??` characters as placeholders for identifiers you would +like to have escaped like this: + +<!-- eslint-disable no-undef --> + +```js +var userId = 1; +var columns = ['username', 'email']; +var sql     = SqlString.format('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId]); +console.log(sql); // SELECT `username`, `email` FROM `users` WHERE id = 1 +``` +**Please note that this last character sequence is experimental and syntax might change** + +When you pass an Object to `.escape()` or `.format()`, `.escapeId()` is used to avoid SQL injection in object keys. + +### Formatting queries + +You can use `SqlString.format` to prepare a query with multiple insertion points, +utilizing the proper escaping for ids and values. A simple example of this follows: + +<!-- eslint-disable no-undef --> + +```js +var userId  = 1; +var inserts = ['users', 'id', userId]; +var sql     = SqlString.format('SELECT * FROM ?? WHERE ?? = ?', inserts); +console.log(sql); // SELECT * FROM `users` WHERE `id` = 1 +``` + +Following this you then have a valid, escaped query that you can then send to the database safely. +This is useful if you are looking to prepare the query before actually sending it to the database. +You also have the option (but are not required) to pass in `stringifyObject` and `timeZone`, +allowing you provide a custom means of turning objects into strings, as well as a +location-specific/timezone-aware `Date`. + +This can be further combined with the `SqlString.raw()` helper to generate SQL +that includes MySQL functions as dynamic vales: + +<!-- eslint-disable no-undef --> + +```js +var userId = 1; +var data   = { email: 'foobar@example.com', modified: SqlString.raw('NOW()') }; +var sql    = SqlString.format('UPDATE ?? SET ? WHERE `id` = ?', ['users', data, userId]); +console.log(sql); // UPDATE `users` SET `email` = 'foobar@example.com', `modified` = NOW() WHERE `id` = 1 +``` + +## License + +[MIT](LICENSE) + +[npm-version-image]: https://img.shields.io/npm/v/sqlstring.svg +[npm-downloads-image]: https://img.shields.io/npm/dm/sqlstring.svg +[npm-url]: https://npmjs.org/package/sqlstring +[travis-image]: https://img.shields.io/travis/mysqljs/sqlstring/master.svg +[travis-url]: https://travis-ci.org/mysqljs/sqlstring +[coveralls-image]: https://img.shields.io/coveralls/mysqljs/sqlstring/master.svg +[coveralls-url]: https://coveralls.io/r/mysqljs/sqlstring?branch=master +[node-image]: https://img.shields.io/node/v/sqlstring.svg +[node-url]: https://nodejs.org/en/download diff --git a/node_modules/sqlstring/index.js b/node_modules/sqlstring/index.js new file mode 100644 index 0000000..4ef5944 --- /dev/null +++ b/node_modules/sqlstring/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/SqlString'); diff --git a/node_modules/sqlstring/lib/SqlString.js b/node_modules/sqlstring/lib/SqlString.js new file mode 100644 index 0000000..4567bfa --- /dev/null +++ b/node_modules/sqlstring/lib/SqlString.js @@ -0,0 +1,237 @@ +var SqlString  = exports; + +var ID_GLOBAL_REGEXP    = /`/g; +var QUAL_GLOBAL_REGEXP  = /\./g; +var CHARS_GLOBAL_REGEXP = /[\0\b\t\n\r\x1a\"\'\\]/g; // eslint-disable-line no-control-regex +var CHARS_ESCAPE_MAP    = { +  '\0'   : '\\0', +  '\b'   : '\\b', +  '\t'   : '\\t', +  '\n'   : '\\n', +  '\r'   : '\\r', +  '\x1a' : '\\Z', +  '"'    : '\\"', +  '\''   : '\\\'', +  '\\'   : '\\\\' +}; + +SqlString.escapeId = function escapeId(val, forbidQualified) { +  if (Array.isArray(val)) { +    var sql = ''; + +    for (var i = 0; i < val.length; i++) { +      sql += (i === 0 ? '' : ', ') + SqlString.escapeId(val[i], forbidQualified); +    } + +    return sql; +  } else if (forbidQualified) { +    return '`' + String(val).replace(ID_GLOBAL_REGEXP, '``') + '`'; +  } else { +    return '`' + String(val).replace(ID_GLOBAL_REGEXP, '``').replace(QUAL_GLOBAL_REGEXP, '`.`') + '`'; +  } +}; + +SqlString.escape = function escape(val, stringifyObjects, timeZone) { +  if (val === undefined || val === null) { +    return 'NULL'; +  } + +  switch (typeof val) { +    case 'boolean': return (val) ? 'true' : 'false'; +    case 'number': return val + ''; +    case 'object': +      if (val instanceof Date) { +        return SqlString.dateToString(val, timeZone || 'local'); +      } else if (Array.isArray(val)) { +        return SqlString.arrayToList(val, timeZone); +      } else if (Buffer.isBuffer(val)) { +        return SqlString.bufferToString(val); +      } else if (typeof val.toSqlString === 'function') { +        return String(val.toSqlString()); +      } else if (stringifyObjects) { +        return escapeString(val.toString()); +      } else { +        return SqlString.objectToValues(val, timeZone); +      } +    default: return escapeString(val); +  } +}; + +SqlString.arrayToList = function arrayToList(array, timeZone) { +  var sql = ''; + +  for (var i = 0; i < array.length; i++) { +    var val = array[i]; + +    if (Array.isArray(val)) { +      sql += (i === 0 ? '' : ', ') + '(' + SqlString.arrayToList(val, timeZone) + ')'; +    } else { +      sql += (i === 0 ? '' : ', ') + SqlString.escape(val, true, timeZone); +    } +  } + +  return sql; +}; + +SqlString.format = function format(sql, values, stringifyObjects, timeZone) { +  if (values == null) { +    return sql; +  } + +  if (!Array.isArray(values)) { +    values = [values]; +  } + +  var chunkIndex        = 0; +  var placeholdersRegex = /\?+/g; +  var result            = ''; +  var valuesIndex       = 0; +  var match; + +  while (valuesIndex < values.length && (match = placeholdersRegex.exec(sql))) { +    var len = match[0].length; + +    if (len > 2) { +      continue; +    } + +    var value = len === 2 +      ? SqlString.escapeId(values[valuesIndex]) +      : SqlString.escape(values[valuesIndex], stringifyObjects, timeZone); + +    result += sql.slice(chunkIndex, match.index) + value; +    chunkIndex = placeholdersRegex.lastIndex; +    valuesIndex++; +  } + +  if (chunkIndex === 0) { +    // Nothing was replaced +    return sql; +  } + +  if (chunkIndex < sql.length) { +    return result + sql.slice(chunkIndex); +  } + +  return result; +}; + +SqlString.dateToString = function dateToString(date, timeZone) { +  var dt = new Date(date); + +  if (isNaN(dt.getTime())) { +    return 'NULL'; +  } + +  var year; +  var month; +  var day; +  var hour; +  var minute; +  var second; +  var millisecond; + +  if (timeZone === 'local') { +    year        = dt.getFullYear(); +    month       = dt.getMonth() + 1; +    day         = dt.getDate(); +    hour        = dt.getHours(); +    minute      = dt.getMinutes(); +    second      = dt.getSeconds(); +    millisecond = dt.getMilliseconds(); +  } else { +    var tz = convertTimezone(timeZone); + +    if (tz !== false && tz !== 0) { +      dt.setTime(dt.getTime() + (tz * 60000)); +    } + +    year       = dt.getUTCFullYear(); +    month       = dt.getUTCMonth() + 1; +    day         = dt.getUTCDate(); +    hour        = dt.getUTCHours(); +    minute      = dt.getUTCMinutes(); +    second      = dt.getUTCSeconds(); +    millisecond = dt.getUTCMilliseconds(); +  } + +  // YYYY-MM-DD HH:mm:ss.mmm +  var str = zeroPad(year, 4) + '-' + zeroPad(month, 2) + '-' + zeroPad(day, 2) + ' ' + +    zeroPad(hour, 2) + ':' + zeroPad(minute, 2) + ':' + zeroPad(second, 2) + '.' + +    zeroPad(millisecond, 3); + +  return escapeString(str); +}; + +SqlString.bufferToString = function bufferToString(buffer) { +  return 'X' + escapeString(buffer.toString('hex')); +}; + +SqlString.objectToValues = function objectToValues(object, timeZone) { +  var sql = ''; + +  for (var key in object) { +    var val = object[key]; + +    if (typeof val === 'function') { +      continue; +    } + +    sql += (sql.length === 0 ? '' : ', ') + SqlString.escapeId(key) + ' = ' + SqlString.escape(val, true, timeZone); +  } + +  return sql; +}; + +SqlString.raw = function raw(sql) { +  if (typeof sql !== 'string') { +    throw new TypeError('argument sql must be a string'); +  } + +  return { +    toSqlString: function toSqlString() { return sql; } +  }; +}; + +function escapeString(val) { +  var chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex = 0; +  var escapedVal = ''; +  var match; + +  while ((match = CHARS_GLOBAL_REGEXP.exec(val))) { +    escapedVal += val.slice(chunkIndex, match.index) + CHARS_ESCAPE_MAP[match[0]]; +    chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex; +  } + +  if (chunkIndex === 0) { +    // Nothing was escaped +    return "'" + val + "'"; +  } + +  if (chunkIndex < val.length) { +    return "'" + escapedVal + val.slice(chunkIndex) + "'"; +  } + +  return "'" + escapedVal + "'"; +} + +function zeroPad(number, length) { +  number = number.toString(); +  while (number.length < length) { +    number = '0' + number; +  } + +  return number; +} + +function convertTimezone(tz) { +  if (tz === 'Z') { +    return 0; +  } + +  var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/); +  if (m) { +    return (m[1] === '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60; +  } +  return false; +} diff --git a/node_modules/sqlstring/package.json b/node_modules/sqlstring/package.json new file mode 100644 index 0000000..d487f85 --- /dev/null +++ b/node_modules/sqlstring/package.json @@ -0,0 +1,47 @@ +{ +  "name": "sqlstring", +  "description": "Simple SQL escape and format for MySQL", +  "version": "2.3.2", +  "contributors": [ +    "Adri Van Houdt <adri.van.houdt@gmail.com>", +    "Douglas Christopher Wilson <doug@somethingdoug.com>", +    "fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)", +    "Kevin Jose Martin <kevin@tiliq.com>", +    "Nathan Woltman <nwoltman@outlook.com>", +    "Sergej Sintschilin <seregpie@gmail.com>" +  ], +  "license": "MIT", +  "keywords": [ +    "sqlstring", +    "sql", +    "escape", +    "sql escape" +  ], +  "repository": "mysqljs/sqlstring", +  "devDependencies": { +    "beautify-benchmark": "0.2.4", +    "benchmark": "2.1.4", +    "eslint": "5.16.0", +    "eslint-plugin-markdown": "1.0.2", +    "nyc": "15.0.0", +    "urun": "0.0.8", +    "utest": "0.0.8" +  }, +  "files": [ +    "lib/", +    "HISTORY.md", +    "LICENSE", +    "README.md", +    "index.js" +  ], +  "engines": { +    "node": ">= 0.6" +  }, +  "scripts": { +    "bench": "node benchmark/index.js", +    "lint": "eslint --plugin markdown --ext js,md .", +    "test": "node test/run.js", +    "test-ci": "nyc --reporter=text npm test", +    "test-cov": "nyc --reporter=html --reporter=text npm test" +  } +}  | 
