Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
The main goal of this project to create the fast MongoDB-like database engine library which can be embed into C/C++ applications under terms of LGPL license.
EJDB is the C library based on modified version of Tokyo Cabinet.
JSON representation of queries and data implemented with API based on C BSON
$stror
$strand
var EJDB = require("ejdb");
//Open zoo DB
var jb = EJDB.open("zoo", EJDB.DEFAULT_OPEN_MODE | EJDB.JBOTRUNC);
var parrot1 = {
"name" : "Grenny",
"type" : "African Grey",
"male" : true,
"age" : 1,
"birthdate" : new Date(),
"likes" : ["green color", "night", "toys"],
"extra1" : null
};
var parrot2 = {
"name" : "Bounty",
"type" : "Cockatoo",
"male" : false,
"age" : 15,
"birthdate" : new Date(),
"likes" : ["sugar cane"]
};
jb.save("parrots", [parrot1, parrot2], function(err, oids) {
if (err) {
console.error(err);
return;
}
console.log("Grenny OID: " + parrot1["_id"]);
console.log("Bounty OID: " + parrot2["_id"]);
jb.find("parrots",
{"likes" : "toys"},
{"$orderby" : {"name" : 1}},
function(err, cursor, count) {
if (err) {
console.error(err);
return;
}
console.log("Found " + count + " parrots");
while (cursor.next()) {
console.log(cursor.field("name") + " likes toys!");
}
cursor.close(); //It's not mandatory to close cursor explicitly
jb.close(); //Close the database
});
});
System libraries:
On Debian/Ubuntu linux you can install it as follows:
sudo apt-get install g++ libcunit1 libcunit1-dev zlib1g zlib1g-dev
Installation from node package manager:
npm install ejdb
Open database. Return database instance handle object.
Default open mode: JBOWRITER | JBOCREAT
.
This is blocking function.
Arguments
[openMode=JBOWRITER | JBOCREAT]
Bitmast of open modes:
- JBOREADER
Open as a reader.
- JBOWRITER
Open as a writer.
- JBOCREAT
Create if db file not exists
- JBOTRUNC
Truncate db.Close database.
If database was not opened it does nothing.
This is blocking function.
Automatically creates new collection if it does't exists.
Collection options copts
applied only for newly created collection.
For existing collections copts
takes no effect.
This is blocking function.
Arguments
[copts]
Collection options.Remove collection.
Call variations:
removeCollection(cname)
removeCollection(cname, cb)
removeCollection(cname, prune, cb)
Arguments
[prune=false]
If true the collection data will erased from disk.[cb]
Callback args: (error)Save/update specified JSON objects in the collection.
If collection with cname
does not exists it will be created.
Each persistent object has unique identifier (OID) placed in the _id
property.
If a saved object does not have _id
it will be autogenerated.
To identify and update object it should contains _id
property.
Call variations:
save(cname, json object, [cb])
save(cname, <Array of json objects>, [cb])
Arguments
[cb]
Callback args: (error, {Array} of OIDs for saved objects)Loads JSON object identified by OID from the collection.
Arguments
obj
: Retrieved JSON object or NULL if it is not found.Removes JSON object from the collection.
Arguments
Supported queries:
- Simple matching of String OR Number OR Array value:
- {'json.field.path' : 'val', ...}
- $not Negate operation.
- {'json.field.path' : {'$not' : val}} //Field not equal to val
- {'json.field.path' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
- $begin String starts with prefix
- {'json.field.path' : {'$begin' : prefix}}
- $gt, $gte (>, >=) and $lt, $lte for number types:
- {'json.field.path' : {'$gt' : number}, ...}
- $bt Between for number types:
- {'json.field.path' : {'$bt' : [num1, num2]}}
- $in String OR Number OR Array val matches to value in specified array:
- {'json.field.path' : {'$in' : [val1, val2, val3]}}
- $nin - Not IN
- $strand String tokens OR String array val matches all tokens in specified array:
- {'json.field.path' : {'$strand' : [val1, val2, val3]}}
- $stror String tokens OR String array val matches any token in specified array:
- {'json.field.path' : {'$stror' : [val1, val2, val3]}}
- $exists Field existence matching:
- {'json.field.path' : {'$exists' : true|false}}
NOTE: Negate operations: $not and $nin not using indexes
so they can be slow in comparison to other matching operations.
NOTE: Only one index can be used in search query operation.
QUERY HINTS (specified by `hints` argument):
- $max Maximum number in the result set
- $skip Number of skipped results in the result set
- $orderby Sorting order of query fields.
Eg: ORDER BY field1 ASC, field2 DESC
hints: {
"$orderby" : {
"field1" : 1,
"field2" : -1
}
}
Many C API query examples can be found in `tcejdb/testejdb/t2.c` test case.
To traverse selected records cursor object is used:
- Cursor#next() Move cursor to the next record and returns true if next record exists.
- Cursor#hasNext() Returns true if cursor can be placed to the next record.
- Cursor#field(name) Retrieve value of the specified field of the current JSON object record.
- Cursor#object() Retrieve whole JSON object with all fields.
- Cursor#reset() Reset cursor to its initial state.
- Cursor#length Read-only property: Number of records placed into cursor.
- Cursor#pos Read/Write property: You can set cursor position: 0 <= pos < length
- Cursor#close() Closes cursor and free cursor resources. Cursor cant be used in closed state.
Call variations of find():
- find(cname, qobj, cb)
- find(cname, qobj, hints, cb)
- find(cname, qobj, qobjarr, cb)
- find(cname, qobj, qobjarr, hints, cb)
Arguments
[orarr]
Array of additional OR query objects (joined with OR predicate).[hints]
JSON object with query hints.cursor
: Cursor object to traverse records
count
: Total number of selected recordsCall variations of findOne():
findOne(cname, qobj, cb)
findOne(cname, qobj, hints, cb)
findOne(cname, qobj, qobjarr, cb)
findOne(cname, qobj, qobjarr, hints, cb)
Arguments
[orarr]
Array of additional OR query objects (joined with OR predicate).[hints]
JSON object with query hints.obj
Retrieved JSON object or NULL if it is not found.Call variations of count():
count(cname, qobj, cb)
count(cname, qobj, hints, cb)
count(cname, qobj, qobjarr, cb)
count(cname, qobj, qobjarr, hints, cb)
Arguments
[orarr]
Array of additional OR query objects (joined with OR predicate).[hints]
JSON object with query hints.count
: Number of matching records.Arguments
Arguments
[cb]
Optional callback function. Callback args: (error)Arguments
[cb]
Optional callback function. Callback args: (error)Ensure index presence of String|Number|Array type for JSON field path
Arguments
[cb]
Optional callback function. Callback args: (error)Rebuild index of String|Number|Array type for JSON field path
Arguments
[cb]
Optional callback function. Callback args: (error)Drop index of String|Number|Array type for JSON field path
Arguments
[cb]
Optional callback function. Callback args: (error)#include <tcejdb/ejdb.h>
static EJDB *jb;
int main() {
jb = ejdbnew();
if (!ejdbopen(jb, "addressbook", JBOWRITER | JBOCREAT | JBOTRUNC)) {
return 1;
}
//Get or create collection 'contacts'
EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
bson bsrec;
bson_oid_t oid;
//Insert one record:
//JSON: {'name' : 'Bruce', 'phone' : '333-222-333', 'age' : 58}
bson_init(&bsrec);
bson_append_string(&bsrec, "name", "Bruce");
bson_append_string(&bsrec, "phone", "333-222-333");
bson_append_int(&bsrec, "age", 58);
bson_finish(&bsrec);
//Save BSON
ejdbsavebson(coll, &bsrec, &oid);
fprintf(stderr, "\nSaved Bruce");
bson_destroy(&bsrec);
//Now execute query
//QUERY: {'name' : {'$begin' : 'Bru'}} //Name starts with 'Bru' string
bson bq1;
bson_init_as_query(&bq1);
bson_append_start_object(&bq1, "name");
bson_append_string(&bq1, "$begin", "Bru");
bson_append_finish_object(&bq1);
bson_finish(&bq1);
EJQ *q1 = ejdbcreatequery(jb, &bq1, NULL, 0, NULL);
uint32_t count;
TCLIST *res = ejdbqrysearch(coll, q1, &count, 0, NULL);
fprintf(stderr, "\n\nRecords found: %d\n", count);
//Now print the result set records
for (int i = 0; i < TCLISTNUM(res); ++i) {
void *bsdata = TCLISTVALPTR(res, i);
bson_print_raw(stderr, bsdata, 0);
}
fprintf(stderr, "\n");
//Dispose result set
tclistdel(res);
//Dispose query
ejdbquerydel(q1);
bson_destroy(&bq1);
//Close database
ejdbclose(jb);
ejdbdel(jb);
return 0;
}
System libraries:
On Debian/Ubuntu linux you can install it as follows:
sudo apt-get install gcc libcunit1 libcunit1-dev zlib1g zlib1g-dev
cd ./tcejdb
./configure --disable-bzip --prefix=<installation prefix> && make && make check
make install
<tcejdb/ejdb.h>
EJDB API presented in ejdb.h C header file.
JSON processing API: bson.h
/**
* Create query object.
* Sucessfully created queries must be destroyed with ejdbquerydel().
*
* EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
*
* - Supported queries:
* - Simple matching of String OR Number OR Array value:
* - {'json.field.path' : 'val', ...}
* - $not Negate operation.
* - {'json.field.path' : {'$not' : val}} //Field not equal to val
* - {'json.field.path' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
* - $begin String starts with prefix
* - {'json.field.path' : {'$begin' : prefix}}
* - $gt, $gte (>, >=) and $lt, $lte for number types:
* - {'json.field.path' : {'$gt' : number}, ...}
* - $bt Between for number types:
* - {'json.field.path' : {'$bt' : [num1, num2]}}
* - $in String OR Number OR Array val matches to value in specified array:
* - {'json.field.path' : {'$in' : [val1, val2, val3]}}
* - $nin - Not IN
* - $strand String tokens OR String array val matches all tokens in specified array:
* - {'json.field.path' : {'$strand' : [val1, val2, val3]}}
* - $stror String tokens OR String array val matches any token in specified array:
* - {'json.field.path' : {'$stror' : [val1, val2, val3]}}
* - $exists Field existence matching:
* - {'json.field.path' : {'$exists' : true|false}}
*
* NOTE: Negate operations: $not and $nin not using indexes
* so they can be slow in comparison to other matching operations.
*
* NOTE: Only one index can be used in search query operation.
*
* QUERY HINTS (specified by `hints` argument):
* - $max Maximum number in the result set
* - $skip Number of skipped results in the result set
* - $orderby Sorting order of query fields.
* Eg: ORDER BY field1 ASC, field2 DESC
* hints: {
* "$orderby" : {
* "field1" : 1,
* "field2" : -1
* }
* }
*
* Many query examples can be found in `testejdb/t2.c` test case.
*
* @param EJDB database handle.
* @param qobj Main BSON query object.
* @param orqobjs Array of additional OR query objects (joined with OR predicate).
* @param orqobjsnum Number of OR query objects.
* @param hints BSON object with query hints.
* @return On success return query handle. On error returns NULL.
*/
EJDB_EXPORT EJQ* ejdbcreatequery(EJDB *jb, bson *qobj, bson *orqobjs, int orqobjsnum, bson *hints);
You can find some code samples in:
EJDB database files structure
.
├── <dbname>
├── <dbname>_<collection1>
├── ...
├── <dbname>_<collectionN>
└── <dbname>_<collectionN>_<fieldpath>.<index ext>
Where
<dbname>
- name of database. It is metadata DB.<collectionN>
- name of collection. Collection database.<fieldpath>
- JSON field path used in index<index ext>
- Collection index extension:
.lex
String index.dec
Number index.tok
Array indexFAQs
EJDB - Embedded JSON Database engine
The npm package ejdb receives a total of 123 weekly downloads. As such, ejdb popularity was classified as not popular.
We found that ejdb demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.