
Research
Namastex.ai npm Packages Hit with TeamPCP-Style CanisterWorm Malware
Malicious Namastex.ai npm packages appear to replicate TeamPCP-style Canister Worm tradecraft, including exfiltration and self-propagation.
##DoQmentDB - A Promise-Based DocumentDB Client
DoQmentDB is a tiny layer that provides the simplicity of MongoDB for DocumentDB users(support schema, hooks/middleware, atomic-transactions, udf and more).
##Table of contents:
#Get Started (1) You can install DoQmentDB using 2 different methods:
(2) Add to your project:
var DoqmentDB = require('doqmentdb');
(3) Start Playing with DoqmentDB:
var DoQmentDB = require('doqmentdb');
// Create DocumentDB connection
var connection = new (require('documentdb').DocumentClient)(HOST, OPTIONS);
// Pass connection and database-name, if `test` is not exist it will create one.
var db = new DoQmentDB(connection, 'test');
// Create a CollectionManager instance, if `users` is not exist it will create one.
var users = db.use('users');
// Using schema
users.schema(model);
// Add hooks(see `users` full example)
users.pre('save', function(next) {
var doc = this;
doc.createdAt = new Date().toString();
next();
});
// Each http function returns a `Promise` with two specific methods: success and error.
users.create({ name: '6534' })
.then(console.log);
users.findById(1)
.then(console.log);
users.findAndRemove({ isAdmin: false })
.then(console.log);
#Database
Create a DatabaseManager by passing connection and databaseName.
var DoQmentDB = require('doqmentdb');
// Create DocumentDB connection
var connection = new (require('documentdb').DocumentClient)(HOST, OPTIONS);
// if `test` is not exist it will create one
var db = new DoQmentDB(connection, 'test');
##create
Get name and crete new collection in the used db.
Usage: db.create(string)
Aliases: insert
Returns: Object
db.create('users')
.then(console.log);
##getDatabase
Return the used database.
Usage: db.getDatabase()
db.getDatabase()
.then(console.log);
##find
find collection by given object params.
Note: to return all documents, omit params argument or pass an empty object({}).
Usage: db.find(object[optional])
Returns: Array
db.find()
.then(console.log); // Return all collections
db.find({ id: 'users' })
.then(console.log); // Return collections where id equal to `users`
##findById
find collection by given string id.
Usage: db.findById(string)
Returns: Object
db.findById('users')
.then(console.log);
##findOrCreate
get object properties, search for collection, if it not exist create one.
Usage: db.findOrCreate(object)
Returns: Object
db.findOrCreate({ name: 'users', id: '#1' })
.then(console.log);
##remove
get collection id as a String, if it exist - remove it and return undefined, else return false.
Usage: db.remove(string)
Returns: undefined or Boolean
db.remove('test')
.then(console.log);
##use
get collection name and return CollectionManager instance.
Note: if the given collection is not exist it will create one.
Usage: var coll = db.use(string);
Returns: object instanceof CollectionManager
var users = db.use('users'); // This operation is not async
#Collection
Create a CollectionManager by passing to .use function a collection name.
var users = db.use('users');
console.log(users.constructor.name); // Collection
##create
get object properties, and create new document under the used collection.
Usage: users.create(object)
Aliases: insert
Returns: Object
users.create({ name: 'Ariel', admin: true })
.then(console.log); // { name: 'Ariel', admin: true, id: '8...31', _self: ... }
##createOrUpdate
create a new document under the current collection, or update an existing document with the same id.
Usage: users.createOrUpdate(object)
Aliases: upsert
Returns: Object
users.upsert({ id: 'my_user_id', admin: true })
.then(console.log); // { id: 'my_user_id', admin: true, _self: ... }
##getCollection
return the used collection.
Usage: users.getCollection()
users.getCollection()
.then(console.log);
##find
get object properties and return array of results.
Usage: users.find(object)
Note: to return all collections, omit params argument or pass an empty object({}).
Returns: Array
users.find({ active: true })
.then(console.log);
##findOne
get object properties and return the first matching result.
Usage: users.findOne(object)
Returns: Object
users.findOne({ active: true, name: 'Bar' })
.then(console.log);
##findById
find document by giving a string id.
Usage: users.findById(string)
Returns: Object
users.findById('53...3')
.then(console.log);
##findAndRemove
get object properties to search, find the equivalents and remove them.
Usage: users.findAndRemove(object)
Returns: Array
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $ sign.
users.findAndRemove({ name: 'Ariel' })
.then(console.log);
// Using stored procedure
users.$findAndRemove({ name: 'Ariel' })
.then(console.log);
// Remove all users
users.findAndRemove({})
.then(console.log);
##findOneAndRemove
get object properties, and remove the first matching result.
Usage: users.findOneAndRemove(object)
Returns: undefined or Boolean
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $ sign.
users.findOneAndRemove({ name: 'Ariel', admin: true })
.then(console.log);
// Using stored procedure
users.$findOneAndRemove({ name: 'Ariel', admin: true })
.then(console.log);
##findAndModify
get object properties to search, find the equivalents and modify them(extend operation).
Usage: users.findAndModify(object, extend)
Aliases: update
Returns: Array
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $ sign.
users.update({ name: 'Ariel', admin: true }, { admin: false })
.then(console.log);
// Push 'a' and 'b' to `list` field(do it concurrently)
['a', 'b'].forEach(function(ch) {
users.$update({}, { list: { $push: ch } });
});
##findOneAndModify
get object properties and modify(extend operation) the first matching.
Usage: users.findOneAndModify(object, extend)
Aliases: updateOne
Returns: Object
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $ sign.
users.findOneAndModify({ admin: false }, { admin: true })
.then(console.log);
// Using stored procedure
users.$findOneAndModify({ admin: false }, { admin: true })
.then(console.log);
##findOrCreate
get object properties, search for document, if it not exist create one.
Usage: users.findOrCreate(object)
Returns: Object
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $ sign.
users.findOrCreate({ admin: false, name: 'Ariel' })
.then(console.log);
// Using stored procedure
users.$findOrCreate({ admin: false, name: 'Ariel' })
.then(console.log);
#Queries ###Operators
$or OR$and AND$not NOT$nor NOT(... OR ...)$gt >$gte >=$lt <$lte <=$ne <> or !=$in like Array.prototype.some(...)$all like Array.prototype.every(...)$type typeof value$regex new RegExp(...).test(value)$size test array.length###Examples
users.find({ a: 1, b: 2, c: '3' })
// ... r WHERE r.a=1 AND r.b=2 AND r.c="3"
users.find({ $or: [{ a: 2, b: 3}, { c: 3 }] })
// ... r WHERE ((r.a=2 AND r.b=3) OR r.c=3)
users.find({ $not: { a: 1, b: 2, c: 3 } })
// ... r WHERE NOT(r.a=1 AND r.b=2 AND r.c=3)
users.find({ $nor: [ { a: 1 }, { b: 3 }]})
// ... r WHERE NOT(r.a=1 OR r.b=3)
users.find({ $nor: [ { a: 1, b: 1 }, { c: 3 } ] })
// ... r WHERE NOT((r.a=1 AND r.b=1) OR r.c=3)
users.find({ $not: { name: { $gt: 3 }, age: 12 } })
// ... r WHERE NOT(r.name > 3 AND r.age=12)
users.find({ $not: { name: { $ne: 'bar' } } })
// ... r WHERE NOT(r.name <> "bar")
users.find({ $or: [
{ name: { $ne: 'Ariel' } },
{ age: { $lte: 26 } },
{ $and: [
{ isAdmin: { $ne: false } },
{ isUser: { $ne: false } }
]}
]})
// ... r WHERE r.name <> "Ariel" OR r.age <= 26 OR (r.isAdmin <> false AND r.isUser <> false)
users.find({ coins: { $in: 2 } })
// ... r WHERE inUDF(r.coins, 2)
users.find({ $not: { age: { $type: 'number' } } })
// ... r WHERE NOT(typeUDF(r.age, "number"))
#Operations
When using one of the update operations(e.g: .update(), .findAndModify(), etc...), you could use the build-in prototype functions(based on the type) prefixing with $ sign.
Usage: users.update({ ... }, { keyName: { $method: value } })
Note: value could be single or array of arguments.
// Find all, and push 2 to `arr` field
users.update({}, { arr: { $push: 2 } });
// Suffix all users `name` with #
users.update({}, { name: { $concat: '#' } });
// Trim the name from `foo` to `o`
users.update({ name: 'foo' }, { name: { $substr: [1,1] } });
#Schema
Manage your documents with schema.
fields:
type
String, Boolean, Number, etc..).default
regex
/^[a-zA-Z0-9@:%_\+.~#?&//=|/d]{10,}$/).error
regex/type). see: exampleexpose
expose by default is true, unless you set it to false, it's means that all the find operations returns the documents without exposing this fields. see: exampleExample using schema:
schema: model.js
module.exports = {
/**
* @field name
* @default no default value
*/
name: {
type: String,
'default': ''
},
/**
* @field email
* @default no default value
* @regex email, min-length = 10
*/
email: {
type: String,
'default': '',
regex: /^[a-zA-Z0-9@:%_\+.~#?&//=|/d]{10,}$/,
error: '`email` must be type string, valid email address, and least 10 chars',
expose: true
},
/**
* @field password
* @default no default value
* @regex password
*/
password: {
type: String,
'default': '',
regex: /^.*(?=.{8,})(?=.*[a-zA-Z])(?=.*\d)(?=.*[!#$%&? "]).*$/,
error: '`password` must be type string, contain 8 chars and at least one number, ' +
'one letter and one unique character such as !#$%&? "',
expose: false
},
/**
* @field isAdmin
* @default false
*/
isAdmin: {
type: Boolean,
'default': false
}
};
using schema(model.js)
var DoQmentDB = require('doqmentdb');
var model = require('./model'); // Get model/schema
var connection = new (require('documentdb') // Create DocumentDB connection
.DocumentClient)(CONFIG.HOST, CONFIG.OPTIONS);
var db = new DoQmentDB(connection, CONFIG.DB); // Create DBManager 'test'
var users = db.use('users'); // Create CollectionManager 'users'
users.schema(model); // Using schema
users.create({ password: 'Ar2!as_s'})
.then(console.log)
.catch(console.log);
/*
[Error:
`email` must be type string, valid email address, and least 10 chars
]
*/
users.create({ name: 'Ariel', email: 'ariel.com', password: 'Ar2!as_s'})
.then(console.log)
.catch(console.log);
/*
[Error:
`email` must be type string, valid email address, and least 10 chars
]
*/
users.create({ name: 'Ariel', email: 'a8m@gm.com', password: 'Ar2!as_s'})
.then(console.log)
.catch(console.log);
/*
{
name: 'Ariel',
email: 'a8m@gm.com',
password: 'Ar2!as_s',
id: '2eb7...c0',
...
}
*/
users.find({})
.then(console.log);
/*
Get all documents but without exposing fields(i.e: omit `password` field)
*/
see: How to architect your models
#Middleware
Middleware/Hooks are executed at the document level(create/save/insert, update, remove/delete).
There are two types of middleware, pre and post.
##pre
Usage: users.pre(operation, callback)
Note: pre middleware are executed one after another, when each middleware calls next.
Example:
users.pre('save', function(next) {
var doc = this;
doc.createdAt = new Date().toString();
next();
}, function(next) {
var doc = this;
doc.updatedAt = new Date().toString();
next();
});
// Do something async
users.pre('save', function(next) {
var doc = this;
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(doc.password, salt, function(err, hash) {
doc.password = hash;
next();
});
});
});
// ##Note: the order is importatnt, this example order:
// `createdAt()`, `updatedAT()`, `hash/bcrypt()`, and then the `.create` operation will called
##post
Usage: users.post(operation, callback)
Note: post middleware are executed in parallel.
Example:
users.post('save', function(doc) {
logger(new Date(), doc, 'saved!')
});
#Atomic Transactions
Since v0.2.6 DoQmentDB supports atomic-transactions using a built-in sporcs(i.e: stored procedures) to handle concurrently well.
Note: To perform some operation this way, you should prefix it with $.
Read More: DocumentDB - Atomic Transactions
// Lets take some example of `consuming` from two differents
// Service-Bus queues and update the same `model`/`document`
//
// Note: This also could happen in a distributed system, when two operations happens in parallel
// We have a `stores` collection that holds the `sales` and the `users`
// fields per `store`(a Document)
// We are using the `atomic` version of `update`, because we don't want to lose data
sbs.receiveQueueMessage('sales', function(msg) {
stores.$update({ id: msg.id }, { sales: { $push: msg.sale } });
// Polling again...
});
sbs.receiveQueueMessage('users', function(msg) {
stores.$update({ id: msg.id }, { users: { $push: msg.user } });
// ...
});
#Examples
#Changelog ##0.2.9
##0.2.8
updateOne and $updateOne(the conccurent one)findAndModify)##0.2.6
Since 0.2.6 DoQmentDB support atomic transactions using DocumentDB stored procedures.
Methods that support:
update/findAndModifyfindOneAndModifyfindOrCreatefindAndRemovefindOneAndRemoveIf you want to use one of this methods, you should use them prefix with $ sign.
// Push 'a' and 'b' to `list` field(do it concurrently)
['a', 'b'].forEach(function(ch) {
users.$update({}, { list: { $push: ch } });
});
FAQs
A Promise-Based DocumentDB ODM Client for NodeJS
We found that doqmentdb demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer 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
Malicious Namastex.ai npm packages appear to replicate TeamPCP-style Canister Worm tradecraft, including exfiltration and self-propagation.

Product
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.