+74
| 'use strict'; | ||
| const internals = {}; | ||
| exports.parse = function (text, ...args) { | ||
| // Normalize arguments | ||
| const firstOptions = typeof args[0] === 'object' && args[0]; | ||
| const reviver = args.length > 1 || !firstOptions ? args[0] : undefined; | ||
| const options = (args.length > 1 && args[1]) || firstOptions || {}; | ||
| // Parse normally, allowing exceptions | ||
| const obj = JSON.parse(text, reviver); | ||
| // options.protoAction: 'error' (default) / 'remove' / 'ignore' | ||
| if (options.protoAction === 'ignore') { | ||
| return obj; | ||
| } | ||
| // Ignore null and non-objects | ||
| if (!obj || | ||
| typeof obj !== 'object') { | ||
| return obj; | ||
| } | ||
| // Check original string for potential exploit | ||
| if (text.indexOf('"__proto__"') === -1) { | ||
| return obj; | ||
| } | ||
| // Scan result for proto keys | ||
| internals.scan(obj, options); | ||
| return obj; | ||
| }; | ||
| internals.scan = function (obj, options) { | ||
| let next = [obj]; | ||
| while (next.length) { | ||
| const nodes = next; | ||
| next = []; | ||
| for (const node of nodes) { | ||
| if (node.hasOwnProperty('__proto__')) { | ||
| if (options.protoAction !== 'remove') { | ||
| throw new SyntaxError('Object contains forbidden prototype property'); | ||
| } | ||
| delete node.__proto__; | ||
| } | ||
| for (const key in node) { | ||
| const value = node[key]; | ||
| if (value && | ||
| typeof value === 'object') { | ||
| next.push(node[key]); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }; |
+12
| Copyright (c) 2019, Project contributors. | ||
| All rights reserved. | ||
| Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
| 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
| 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
| 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+17
-31
| { | ||
| "name": "bourne", | ||
| "description": "A simple serverless database stored in a JSON file.", | ||
| "version": "0.4.0", | ||
| "homepage": "https://github.com/andreww8088/bourne", | ||
| "author": { | ||
| "name": "Andrew Burgess", | ||
| "email": "andrew@burgess.io", | ||
| "url": "http://andrewburgess.ca" | ||
| "description": "JSON parse with prototype poisoning protection", | ||
| "version": "1.0.0", | ||
| "repository": "git://github.com/hapijs/bourne", | ||
| "main": "lib/index.js", | ||
| "keywords": [ | ||
| "JSON", | ||
| "parse", | ||
| "safe", | ||
| "prototype" | ||
| ], | ||
| "dependencies": { | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git://github.com/andreww8088/bourne.git" | ||
| "devDependencies": { | ||
| "code": "5.x.x", | ||
| "lab": "18.x.x" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/andreww8088/bourne/issues" | ||
| }, | ||
| "licenses": [ | ||
| { | ||
| "type": "MIT", | ||
| "url": "https://github.com/andreww8088/bourne/blob/master/LICENSE-MIT" | ||
| } | ||
| ], | ||
| "main": "lib/bourne", | ||
| "engines": { | ||
| "node": ">= 0.8.0" | ||
| }, | ||
| "scripts": { | ||
| "test": "grunt nodeunit" | ||
| "test": "lab -a code -t 100 -L", | ||
| "test-cov-html": "lab -a code -r html -o coverage.html" | ||
| }, | ||
| "devDependencies": { | ||
| "grunt-contrib-jshint": "~0.6.4", | ||
| "grunt-contrib-nodeunit": "~0.2.0", | ||
| "grunt-contrib-watch": "~0.5.3", | ||
| "grunt": "~0.4.2" | ||
| }, | ||
| "keywords": [] | ||
| "license": "BSD-3-Clause" | ||
| } |
+32
-18
@@ -1,27 +0,41 @@ | ||
| # bourne | ||
| # Bourne. JSON Bourne. | ||
| A simple serverless database stored in a JSON file. | ||
| `JSON.parse()` drop-in replacement with prototype poisoning protection | ||
| ## Getting Started | ||
| Install the module with: `npm install bourne` | ||
| ## Introduction | ||
| ```javascript | ||
| var bourne = require('bourne'); | ||
| bourne.awesome(); // "awesome" | ||
| Consider this: | ||
| ``` | ||
| > const a = '{"__proto__":{ "b":5}}'; | ||
| '{"__proto__":{ "b":5}}' | ||
| ## Documentation | ||
| _(Coming soon)_ | ||
| > const b = JSON.parse(a); | ||
| { __proto__: { b: 5 } } | ||
| ## Examples | ||
| _(Coming soon)_ | ||
| > b.b; | ||
| undefined | ||
| ## Contributing | ||
| In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). | ||
| > const c = Object.assign({}, b); | ||
| {} | ||
| ## Release History | ||
| _(Nothing yet)_ | ||
| > c.b | ||
| 5 | ||
| ``` | ||
| ## License | ||
| Copyright (c) 2014 Andrew Burgess | ||
| Licensed under the MIT license. | ||
| The problem is that `JSON.parse()` retains the `__proto__` property as a plain object key. By | ||
| itself, this is not a security issue. However, as soon as that object is assigned to another or | ||
| iterated on and values copied, the `__proto__` property leaks and becomes the object's prototype. | ||
| ## API | ||
| ### `Bourne.parse(text, [reviver], [options])` | ||
| Parses a given JSON-formatted text into an object where: | ||
| - `text` - the JSON text string. | ||
| - `reviver` - the `JSON.parse()` optional `reviver` argument. | ||
| - `options` - optional configuration object where: | ||
| - `protoAction` - optional string with one of: | ||
| - `'error'` - throw a `SyntaxError` when a `__proto__` key is found. This is the default value. | ||
| - `'remove'` - deletes any `__proto__` keys from the result object. | ||
| - `'ignore'` - skips all validation (same as calling `JSON.parse()` directly). |
-14
| { | ||
| "curly": true, | ||
| "eqeqeq": true, | ||
| "immed": true, | ||
| "latedef": "nofunc", | ||
| "newcap": true, | ||
| "noarg": true, | ||
| "sub": true, | ||
| "undef": true, | ||
| "unused": true, | ||
| "boss": true, | ||
| "eqnull": true, | ||
| "node": true | ||
| } |
-48
| 'use strict'; | ||
| module.exports = function(grunt) { | ||
| // Project configuration. | ||
| grunt.initConfig({ | ||
| nodeunit: { | ||
| files: ['test/**/*_test.js'], | ||
| }, | ||
| jshint: { | ||
| options: { | ||
| jshintrc: '.jshintrc' | ||
| }, | ||
| gruntfile: { | ||
| src: 'Gruntfile.js' | ||
| }, | ||
| lib: { | ||
| src: ['lib/**/*.js'] | ||
| }, | ||
| test: { | ||
| src: ['test/**/*.js'] | ||
| }, | ||
| }, | ||
| watch: { | ||
| gruntfile: { | ||
| files: '<%= jshint.gruntfile.src %>', | ||
| tasks: ['jshint:gruntfile'] | ||
| }, | ||
| lib: { | ||
| files: '<%= jshint.lib.src %>', | ||
| tasks: ['jshint:lib', 'nodeunit'] | ||
| }, | ||
| test: { | ||
| files: '<%= jshint.test.src %>', | ||
| tasks: ['jshint:test', 'nodeunit'] | ||
| }, | ||
| }, | ||
| }); | ||
| // These plugins provide necessary tasks. | ||
| grunt.loadNpmTasks('grunt-contrib-nodeunit'); | ||
| grunt.loadNpmTasks('grunt-contrib-jshint'); | ||
| grunt.loadNpmTasks('grunt-contrib-watch'); | ||
| // Default task. | ||
| grunt.registerTask('default', ['jshint', 'nodeunit']); | ||
| }; |
-234
| /* | ||
| * bourne | ||
| * https://github.com/andreww8088/bourne | ||
| * | ||
| * Copyright (c) 2014 Andrew Burgess | ||
| * Licensed under the MIT license. | ||
| */ | ||
| (function () { | ||
| 'use strict'; | ||
| var store = {}; | ||
| if (typeof require !== 'undefined') { | ||
| var fs = require('fs'); | ||
| store.exists = fs.existsSync.bind(fs); | ||
| store.remove = fs.unlinkSync.bind(fs); | ||
| store.get = fs.readFileSync.bind(fs); | ||
| store.set = fs.writeFile.bind(fs); | ||
| } else { | ||
| store.exists = function (key) { return localStorage.getItem(key) !== null; }; | ||
| store.remove = localStorage.removeItem.bind(localStorage); | ||
| store.get = localStorage.getItem.bind(localStorage); | ||
| store.set = function (key, value, callback) { localStorage.setItem(key, value); callback && callback(); }; | ||
| } | ||
| function noStore() { | ||
| var data; | ||
| return { | ||
| exists: function () { return false; }, | ||
| remove: function () { }, | ||
| get : function () { return data; }, | ||
| set : function (key, value, callback) { data = value; callback && callback(); } | ||
| }; | ||
| } | ||
| var Bourne = function (name, options) { | ||
| options = options || {}; | ||
| this.name = name; | ||
| this.data = []; | ||
| this._id = 1; | ||
| if (options.temp) { | ||
| this.store = noStore(); | ||
| } else { | ||
| this.store = options.store || store; | ||
| } | ||
| if (this.store.exists(this.name)) { | ||
| if (options.reset) { | ||
| this.store.remove(name); | ||
| } else { | ||
| this.data = JSON.parse(this.store.get(name) || {}); | ||
| this._id = Math.max.apply(Math, this.data.map(function (r) { return r.id; })) + 1; | ||
| } | ||
| } else { | ||
| this.store.set(this.name, JSON.stringify(this.data)); | ||
| } | ||
| // Lazy Method | ||
| // if (this.store.exists(this.name) && options && !option.reset) { | ||
| // this.data = json.parse(this.store.get(name) || {}); | ||
| // this._id = math.max.apply(math, this.data.map(function (r) { return r.id; })); | ||
| // } | ||
| }; | ||
| Bourne.prototype.insert = function (record, callback) { | ||
| record.id = this._id++; | ||
| this.data.push(record); | ||
| this.store.set(this.name, JSON.stringify(this.data), function () { | ||
| callback && callback(null, record); | ||
| }); | ||
| }; | ||
| Bourne.prototype.insertAll = function (records, callback) { | ||
| var ids = []; | ||
| records.forEach(function (record) { | ||
| record.id = this._id++; | ||
| ids.push(record.id); | ||
| this.data.push(record); | ||
| }.bind(this)); | ||
| this.store.set(this.name, JSON.stringify(this.data), function () { | ||
| if (callback) this.find({ id: { $in: ids }}, callback); | ||
| }.bind(this)); | ||
| }; | ||
| var operators = { | ||
| $lt: function (key, value, record) { | ||
| return record[key] < value; | ||
| }, | ||
| $gt: function (key, value, record) { | ||
| return record[key] > value; | ||
| }, | ||
| $lte: function (key, value, record) { | ||
| return record[key] <= value; | ||
| }, | ||
| $in: function (key, values, record) { | ||
| for (var i = 0; i < values.length; i++) { | ||
| if (record[key] === values[i]) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| }; | ||
| Bourne.operator = function (name, fn) { | ||
| if (operators[name]) { | ||
| throw 'operator "' + name + '" already exists.' | ||
| } | ||
| operators[name] = fn; | ||
| }; | ||
| function createFilter(query, defaultReturn) { | ||
| return function (record) { | ||
| for (var key in query) { | ||
| if (query.hasOwnProperty(key)) { | ||
| if (typeof query[key] !== 'object') { | ||
| if (!record[key] || record[key] !== query[key]) { | ||
| return defaultReturn; | ||
| } | ||
| } else { | ||
| for (var op in query[key]) { | ||
| if (query[key].hasOwnProperty(op)) { | ||
| if (!operators[op](key, query[key][op], record)) { | ||
| return defaultReturn; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return !defaultReturn; | ||
| } | ||
| } | ||
| Bourne.prototype.find = function (query, callback) { | ||
| if (typeof callback === 'undefined') { | ||
| callback = query; | ||
| query = {}; | ||
| } | ||
| var data = this.data.filter(createFilter(query, false)); | ||
| callback(null, data); | ||
| }; | ||
| Bourne.prototype.findOne = function (query, callback) { | ||
| this.find(query, function (err, records) { | ||
| callback(err, records[0]); | ||
| }); | ||
| }; | ||
| var updateOperators = { | ||
| $set: function (record, params) { | ||
| for (var prop in params) { | ||
| if (params.hasOwnProperty(prop)) { | ||
| record[prop] = params[prop]; | ||
| } | ||
| } | ||
| }, | ||
| $unset: function (record, params) { | ||
| for (var prop in params) { | ||
| if (record.hasOwnProperty(prop)) { | ||
| delete record[prop]; | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| Bourne.prototype.update = function (query, update, callback) { | ||
| var ids = []; | ||
| if (update.$set) { | ||
| this.find(query, function (err, records) { | ||
| records.forEach(function (record) { | ||
| updateOperators.$set(record, update.$set); | ||
| }); | ||
| this.store.set(this.name, JSON.stringify(this.data), function () { | ||
| if (callback) callback(null, records); | ||
| }.bind(this)); | ||
| }.bind(this)); | ||
| } else if (update.$unset) { | ||
| this.find(query, function (err, records) { | ||
| records.forEach(function (record) { | ||
| updateOperators.$unset(record, update.$unset); | ||
| }); | ||
| this.store.set(this.name, JSON.stringify(this.data), function () { | ||
| if (callback) callback(null, records); | ||
| }.bind(this)); | ||
| }.bind(this)); | ||
| } else { | ||
| this.find(query, function (err, records) { | ||
| records.forEach(function (record) { | ||
| ids.push(record.id); | ||
| }); | ||
| this.delete(query, function () { | ||
| var updatedRecords = ids.map(function (id) { | ||
| var u = JSON.parse(JSON.stringify(update)); | ||
| u.id = id; | ||
| return u; | ||
| }); | ||
| this.data = this.data.concat(updatedRecords); | ||
| this.store.set(this.name, JSON.stringify(this.data), function () { | ||
| if (callback) this.find({ id: { $in: ids }}, callback); | ||
| }.bind(this)); | ||
| }.bind(this)); | ||
| }.bind(this)); | ||
| } | ||
| }; | ||
| Bourne.prototype.delete = function (query, callback) { | ||
| this.data = this.data.filter(createFilter(query, true)); | ||
| this.store.set(this.name, JSON.stringify(this.data), function () { | ||
| callback && callback(null); | ||
| }); | ||
| }; | ||
| Bourne.prototype.destroy = function () { | ||
| if (this.store.exists(this.name)) { | ||
| this.store.remove(this.name); | ||
| } | ||
| this.name = this._id = this.data = null; | ||
| }; | ||
| if (typeof exports !== 'undefined') { | ||
| module.exports = Bourne; | ||
| } else { | ||
| window.Bourne = Bourne; | ||
| } | ||
| }.call(this)); |
Sorry, the diff of this file is not supported yet
| 'use strict'; | ||
| if (typeof require !== 'undefined') { | ||
| var Bourne = require('../lib/bourne.js'); | ||
| var Chance = require('chance'); | ||
| } | ||
| var c = new Chance(); | ||
| var testName = (typeof __dirname !== 'undefined') ? __dirname + '/' : ''; | ||
| testName += c.string({ pool: 'abcdefghijklmnopqrstuvwxyz' }); | ||
| var testRecord1 = { firstname: c.first(), lastname: c.last(), age: c.age(), birthday: c.birthday() }, | ||
| testRecord2 = { firstname: c.first(), lastname: c.last(), age: c.age(), birthday: c.birthday() }, | ||
| testRecord3 = { firstname: c.first(), lastname: c.last(), age: c.age(), birthday: c.birthday() }; | ||
| this.bourne_test = { | ||
| prepopulated: { | ||
| setUp: function(done) { | ||
| var db = this.db = new Bourne(testName, { reset: true, temp: true }); | ||
| db.insert(testRecord1, function () { | ||
| db.insert(testRecord2, function () { | ||
| db.insert(testRecord3, done); | ||
| }); | ||
| }); | ||
| }, | ||
| tearDown: function (done) { | ||
| this.db.destroy(); | ||
| done(); | ||
| }, | ||
| 'can find records by one key': function (test) { | ||
| this.db.find({ firstname: testRecord1.firstname }, function (err, records) { | ||
| test.equal(records.length, 1, 'should find one record'); | ||
| test.equal(records[0].firstname, testRecord1.firstname, 'names should be equal'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'can find records by multiple keys': function (test) { | ||
| this.db.find({ firstname: testRecord1.firstname, age: testRecord1.age }, function (err, records) { | ||
| test.equal(records.length, 1, 'should find one record'); | ||
| test.equal(records[0].age, testRecord1.age, 'names should be equal'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'can find multiple records': function (test) { | ||
| var r = { firstname: testRecord1.firstname, age: c.age() }; | ||
| var db = this.db; | ||
| db.insert(r, function () { | ||
| db.find({ firstname: testRecord1.firstname }, function (err, records) { | ||
| test.equal(records.length, 2, '2 records should be found'); | ||
| test.done(); | ||
| }); | ||
| }); | ||
| }, | ||
| 'can use query operators': function (test) { | ||
| var r = { firstname: c.first(), age: 10 }; | ||
| var db = this.db; | ||
| db.insert(r, function () { | ||
| db.find({ age: { $lt: 11 } }, function (err, records) { | ||
| test.notEqual(records.length, 0, 'should have at least 1 record'); | ||
| test.done(); | ||
| }); | ||
| }); | ||
| }, | ||
| 'can find a single record': function (test) { | ||
| this.db.findOne({ firstname: testRecord1.firstname }, function (err, record) { | ||
| test.equal(record.firstname, testRecord1.firstname, 'names should be equal'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'can find all records': function (test) { | ||
| this.db.find(function (err, records) { | ||
| test.equal(records.length, 3, 'should find 3 records'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'can updated records by replacement': function (test) { | ||
| var updatedQuery = { age: 200 }; | ||
| this.db.update({ firstname: testRecord1.firstname }, updatedQuery, function (err, records) { | ||
| updatedQuery.id = records[0].id; | ||
| test.deepEqual(records[0], updatedQuery, 'objects match'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'can update records with $set operator': function (test) { | ||
| this.db.update({ firstname: testRecord1.firstname }, { $set: { firstname: 'XXX' } }, function (err, records) { | ||
| test.equal(records[0].firstname, 'XXX', 'name is updated'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'can update records with $unset operator': function (test) { | ||
| this.db.update({ firstname: testRecord1.firstname }, { $unset: { lastname: '' }}, function (err, records) { | ||
| test.equal(records[0].lastname, undefined, 'no last name'); | ||
| test.done() | ||
| }); | ||
| }, | ||
| 'can delete records': function (test) { | ||
| var db = this.db; | ||
| db.delete({ firstname: testRecord1.firstname }, function () { | ||
| db.find({ firstname: testRecord1.firstname }, function (err, records) { | ||
| test.equal(records.length, 0, 'no records should be found'); | ||
| test.done(); | ||
| }); | ||
| }); | ||
| } | ||
| }, | ||
| 'can create Bourne instance': function(test) { | ||
| test.expect(1); | ||
| test.doesNotThrow(function () { | ||
| var db = new Bourne(testName, { reset: true, temp: true }); | ||
| }); | ||
| test.done(); | ||
| }, | ||
| 'can insert record': function (test) { | ||
| test.expect(2); | ||
| var db = new Bourne(testName, { reset: true, temp: true }); | ||
| db.insert(testRecord1, function (err, record) { | ||
| test.equal(testRecord1.firstname, record.firstname, 'names should be equal'); | ||
| test.equal(record.id, 1, 'id should be 1'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'can restart indexing at the right number': function (test) { | ||
| var str = '[{ "id": 1, "attr": "value" }]'; | ||
| if (typeof require !== 'undefined') { | ||
| var fs = require('fs'); | ||
| fs.writeFileSync(testName, str); | ||
| } else { | ||
| localStorage.setItem(testName, str); | ||
| } | ||
| var db = new Bourne(testName, { log: true }); | ||
| db.insert(testRecord1, function (err, record) { | ||
| test.equal(record.id, 2, 'id should be 2'); | ||
| test.done(); | ||
| db.destroy(); | ||
| }); | ||
| }, | ||
| 'can restart alternate': function (test) { | ||
| var db = new Bourne(testName, { reset: true }); | ||
| db.insert(testRecord1, function (err, record) { | ||
| test.equal(record.id, 1, 'first ID is 1'); | ||
| var db2 = new Bourne(testName, { log: true }); | ||
| db2.insert(testRecord2, function (err, record2) { | ||
| test.equal(record2.id, 2, 'second ID is 2'); | ||
| test.done(); | ||
| db.destroy(); | ||
| db2.destroy(); | ||
| }); | ||
| }); | ||
| }, | ||
| 'can store record persistently': function (test) { | ||
| var db1 = new Bourne(testName, { reset: true }); | ||
| db1.insert(testRecord1, function (err, record) { | ||
| var db2 = new Bourne(testName); | ||
| test.equal(db2.data[0].firstname, testRecord1.firstname, 'names should be equal'); | ||
| test.done(); | ||
| db1.destroy(); | ||
| db2.destroy(); | ||
| }); | ||
| }, | ||
| 'query operators': { | ||
| '$lt': function (test) { | ||
| operatorTest({ age: 10 }, { age: { $lt: 11 } }, function (err, records) { | ||
| test.notEqual(records.length, 0, 'should have at least 1 record'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| '$gt': function (test) { | ||
| operatorTest({ age: 10 }, { age: { $gt: 9 } }, function (err, records) { | ||
| test.notEqual(records.length, 0, 'should have at least 1 record'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| '$lte': function (test) { | ||
| operatorTest({ age: 10 }, { age: { $lte: 10 } }, function (err, records) { | ||
| test.notEqual(records.length, 0, 'should have at least 1 record'); | ||
| test.done(); | ||
| }); | ||
| }, | ||
| 'multiple operators': function (test) { | ||
| operatorTest({ age: 10 }, { age: { $lt: 11, $gt: 9 } }, function (err, records) { | ||
| test.notEqual(records.length, 0, 'should have at least 1 record'); | ||
| test.done(); | ||
| }); | ||
| } | ||
| }, | ||
| 'can insert multiple records': function (test) { | ||
| var db = new Bourne(testName, { reset: true }); | ||
| db.insertAll([testRecord1, testRecord2], function (err, records) { | ||
| test.equal(records.length, 2); | ||
| test.done(); | ||
| db.destroy(); | ||
| }); | ||
| }, | ||
| 'can work with no persistence': function (test) { | ||
| var db = new Bourne(testName, { temp: true }); | ||
| db.insert(testRecord1, function (err, records) { | ||
| var db2 = new Bourne(testName, { temp: true }); | ||
| test.equal(db2.data.length, 0, 'db2 should have no records'); | ||
| test.done(); | ||
| db.destroy(); | ||
| db2.destroy(); | ||
| }); | ||
| } | ||
| }; | ||
| function operatorTest(record, query, cb) { | ||
| var db = new Bourne(testName, { reset: true, temp: true }); | ||
| db.insert(record, function () { | ||
| db.find(query, cb); | ||
| }); | ||
| } |
| /*! | ||
| * Styles taken from qunit.css | ||
| */ | ||
| h1#nodeunit-header, h1.nodeunit-header { | ||
| padding: 15px; | ||
| font-size: large; | ||
| background-color: #06b; | ||
| color: white; | ||
| font-family: 'trebuchet ms', verdana, arial; | ||
| margin: 0; | ||
| } | ||
| h1#nodeunit-header a { | ||
| color: white; | ||
| } | ||
| h2#nodeunit-banner { | ||
| height: 2em; | ||
| border-bottom: 1px solid white; | ||
| background-color: #eee; | ||
| margin: 0; | ||
| font-family: 'trebuchet ms', verdana, arial; | ||
| } | ||
| h2#nodeunit-banner.pass { | ||
| background-color: green; | ||
| } | ||
| h2#nodeunit-banner.fail { | ||
| background-color: red; | ||
| } | ||
| h2#nodeunit-userAgent, h2.nodeunit-userAgent { | ||
| padding: 10px; | ||
| background-color: #eee; | ||
| color: black; | ||
| margin: 0; | ||
| font-size: small; | ||
| font-weight: normal; | ||
| font-family: 'trebuchet ms', verdana, arial; | ||
| font-size: 10pt; | ||
| } | ||
| div#nodeunit-testrunner-toolbar { | ||
| background: #eee; | ||
| border-top: 1px solid black; | ||
| padding: 10px; | ||
| font-family: 'trebuchet ms', verdana, arial; | ||
| margin: 0; | ||
| font-size: 10pt; | ||
| } | ||
| ol#nodeunit-tests { | ||
| font-family: 'trebuchet ms', verdana, arial; | ||
| font-size: 10pt; | ||
| } | ||
| ol#nodeunit-tests li strong { | ||
| cursor:pointer; | ||
| } | ||
| ol#nodeunit-tests .pass { | ||
| color: green; | ||
| } | ||
| ol#nodeunit-tests .fail { | ||
| color: red; | ||
| } | ||
| p#nodeunit-testresult { | ||
| margin-left: 1em; | ||
| font-size: 10pt; | ||
| font-family: 'trebuchet ms', verdana, arial; | ||
| } |
Sorry, the diff of this file is too big to display
| <html> | ||
| <head> | ||
| <title>Nodeunit Test Suite</title> | ||
| <link rel="stylesheet" href="nodeunit.css" type="text/css" media="screen" /> | ||
| <script src="nodeunit.js"></script> | ||
| <script src="../lib/bourne.js"></script> | ||
| <script src='../node_modules/chance/chance.js'></script> | ||
| <script src="bourne_test.js"></script> | ||
| </head> | ||
| <body> | ||
| <h1 id="nodeunit-header">Nodeunit Test Suite</h1> | ||
| <script> | ||
| nodeunit.run({ | ||
| 'test-bourne': bourne_test | ||
| }); | ||
| </script> | ||
| </body> | ||
| </html> |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
2
-50%1
-50%42
50%1
-94.44%4939
-94.26%5
-54.55%48
-97.95%2
100%2
100%