
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.
@rrnara/gremlin-orm
Advanced tools
gremlin-orm is an ORM for graph databases in Node.js. Currently working on Neo4j and Microsoft Azure Cosmos DB with more to come in the future.
$ npm install --save @rrnara/gremlin-orm
const genericPool = require('generic-pool');
const GremlinOrm = require('gremlin-orm');
const Gremlin = require('gremlin');
const Action = require('gremlin-orm/Action');
// const g = new gremlinOrm('neo4j'); // connects to localhost:8182 by default
const dbLogger = (msg) => console.log(msg);
const dbErrorLogger = (msg) => console.error(msg);
const factory = {
create: function() {
const user = '/dbs/--TESTDB--/colls/--TESTGRAPH--';
const primaryKey = '--TEST-PRIMARY-KEY--';
const authenticator = new Gremlin.driver.auth.PlainTextSaslAuthenticator(user, primaryKey);
const options = {
authenticator,
traversalsource: 'g',
rejectUnauthorized: true,
mimeType: 'application/vnd.gremlin-v2.0+json'
};
const client = new Gremlin.driver.Client('wss://--TEST-COSMOSDB--.gremlin.cosmos.azure.com:443/', options);
client.addListener('log', dbLogger);
client.addListener('socketError', dbErrorLogger);
return client;
},
destroy: function(client) {
client.close();
}
};
const connectionPool = genericPool.createPool(factory, { min: 0, max: 10, evictionRunIntervalMillis: 120000, idleTimeoutMillis: 230000 });
connectionPool.on('factoryCreateError', dbErrorLogger);
connectionPool.on('factoryDestroyError', dbErrorLogger);
const g = new GremlinOrm(['azure', 'pk', 'test-partition'], connectionPool, true); // Can use dbLogger as parameter instead of true
const Person = g.define(
'person',
{
name: {
type: g.STRING,
required: true
},
age: {
type: g.NUMBER
}
},
{
getDetails: function(suffix) { return `${this.name} ${suffix}, Age ${this.age}`; }
}
);
Person.create(req.body, (error, result) => {
if (error) {
res.send(error);
}
else {
console.log(result.invoke('getDetails', 'Jr'));
res.send(result);
// result formatted as nice JSON Object
/*
{
"id": "1",
"label": "person",
"name": "Bob",
"age": 20
}
*/
}
});
Initialize the gremlin-orm instance with parameters matching the gremlin-javascript createClient() initialization - with the addition of the dialect argument.
dialect (string or Array): Required argument that takes string ('neo4j') or array (['azure', '<partitionName>', '<defaultPartitionValue>']).client: Gremlin Clientin that the current vertex(es) has out to another vertexRefer to Tinkerpop documentation Only custom query option is Or - to perform Or condition queries
In order to avoid sacrificing the power of Gremlin traversals, method calls in this ORM can take advantage of method chaining. Any read-only method will avoid running its database query and instead pass its Gremlin query string to the next method in the chain if it is not given a callback. Note: All create, update, and delete methods require a callback and can not have more methods chained after.
// Only makes one call to the database
Person.find({'name': 'John'}).findRelated('knows', {'since': '2015'}, (error, result) => {
// Send people John knows to client
})
Additionally, results returned in the form of JSON objects will retain their relevant model methods for additional queries.
// Makes two calls to the database
Person.find({'name': 'John'}), (error, result) => {
let john = result;
john.findRelated('knows', {'since': '2015'}, (error, result) => {
// Send people John knows to client
})
})
This ORM utilizes Model definitions similar to Sequelize to add structure to developing servers around graph databases. Queries outside of the constraints of pre-defined models can be run using the generic .query or .queryRaw.
.define is an alias for defineVertex
.defineVertex defines a new instance of the VertexModel class - see generic and vertex model methods
label: Label to be used on all vertices of this modelschema: A schema object which defines allowed property keys and allowed values/types for each keymethods: An object which defines methods that can be called on instance of modelconst Person = g.define(
'person',
{
name: {
type: g.STRING,
required: true
},
age: {
type: g.NUMBER
}
},
{
getDetails: function (suffix) { return `${this.name} ${suffix}, Age ${this.age}`; }
}
);
.defineEdge defines a new instance of the EdgeModel class - see generic and edge model methods
label: Label to be used on all edges of this modelschema: A schema object which defines allowed property keys and allowed values/types for each keymethods: An object which defines methods that can be called on instance of modelconst Knows = g.defineEdge(
'knows',
{
from: {
type: g.STRING
},
since: {
type: g.DATE
}
},
{
relationshipDetails: function () { return `Since ${this.since}`; }
}
);
The following options are available when defining model schemas:
type: Use Sequelize-like constants to define data types. Date properties will be returned as javascript Date objects unless returning raw data. The following data type constants are currently available with possibly more in the future.
g.STRINGg.NUMBERg.DATEg.BOOLEANrequired (default = false): If true, will not allow saving to database if not present or empty.query takes a raw Gremlin query string and runs it on the object it is called on.
queryString: Gremlin query as a stringraw (optional, default = false): If true, will return the raw data from the graph database instead of normally formatted JSONcallback (optional, required if raw is true): Some callback function with (error, result) arguments. let query = ".as('a').out('created').as('b').in('created').as('c').dedup('a','b').select('a','b','c')"
Person.find({'name': 'John'}).query(query, true, (error, result) => {
// send raw data to client
});
.queryRaw performs a raw query on the gremlin-orm root and returns raw data
queryString: Gremlin query as a stringcallback: Some callback function with (error, result) arguments // query must be a full Gremlin query string
let query = "g.V(1).as('a').out('created').as('b').in('created').as('c').dedup('a','b').select('a','b','c')"
g.queryRaw(query, (error, result) => {
// send raw data to client
});
.update takes a properties object and updates the relevant properties on the model instance it is called on.
props: Object containing key value pairs of properties to updatecallback: Some callback function with (error, result) arguments Person.find({'name': 'John'}).update({'age', 30}, (error, result) => {
// send data to client
});
.delete removes the object(s) it is called on from the database.
callback: Some callback function with (error, result) arguments Person.find({'name', 'John'}, (error, result) => {
if (result) result.delete((error, result) => {
// check if successful delete
});
});
.order sorts the results by a property in ascending or descending order
property: Name of property to order byorder: Order to sort - 'ASC' or 'DESC'callback (optional): Some callback function with (error, result) arguments Person.findAll({'occupation': 'developer'}).order('age', 'DESC', (error, result) => {
// Return oldest developers first
});
.limit limits the query to only the first num objects
num: Max number of results to returncallback (optional): Some callback function with (error, result) arguments Person.find({'name': 'John'}).findEdge('knows').limit(100, (error, result) => {
// Return first 100 people that John knows
});
.range Array range of results returned
start: Starting index of results to return (inclusive)end: Ending index of results to return (exclusive)callback (optional): Some callback function with (error, result) arguments Person.find({'name': 'John'}).findEdge('knows').range(20, 40, (error, result) => {
// Return results 20-39 people that John knows
});
.invoke takes a method name as key and invokes it with arguments provided.
methodName: Method name as string key as defined along with schemaargs (optional): Arguments to pass to the methodPerson.create(req.body, (error, result) => {
if (error) {
res.send(error);
}
else {
console.log(result.invoke('getDetails', 'Jr')); // displays "${result.name} Jr"
}
});
.create creates a new vertex with properties matching props object
props: Object containing key value pairs of properties matching defined Model schemacallback: Some callback function with (error, result) arguments Person.create({'name': 'John', 'age': 30}, (error, result) => {
// Returns the newly created vertex
/*
{
"id": "1",
"label": "person",
"name": "John",
"age": 30
}
*/
});
.find finds the first vertex with properties matching props object
props: Object containing key value pairs of propertiescallback (optional): Some callback function with (error, result) arguments Person.find({'name': 'John'}, (error, result) => {
// Returns first vertex found matching props
/*
{
"id": "1",
"label": "person",
"name": "John",
"age": 30
}
*/
});
.findAll finds the all vertices with properties matching props object
props: Object containing key value pairs of propertiescallback (optional): Some callback function with (error, result) arguments Person.findAll({'age': 30}, (error, result) => {
// Returns array of matching vertices
/*
[
{
"id": "1",
"label": "person",
"name": "John",
"age": 30
},
{
"id": "2",
"label": "person",
"name": "Jane",
"age": 30
}
]
*/
});
.findActionAll find all vertices when particular action is applied on the properties
action: Action providing context to operation to perform over the propsprops: Object containing key value pairs of propertiescallback (optional): Some callback function with (error, result) arguments Person.findActionAll(Action.Or, { name: ['Abc', 'Def'], age: 75 }, (error, results) => {
if (error) {
console.error(error);
} else {
console.log(`Results: ${results.length}`);
console.log(results);
}
})
.createEdge creates new edge relationships from starting vertex(es) to vertex(es) passed in.
edge: Edge model. If a string label is passed, no schema check will be done - edge model is recommendedprops: Object containing key value pairs of properties to place on new edgesvertex: Vertex model instances or vertex model queryboth (optional, default = false): If true, will create edges in both directionscallback: Some callback function with (error, result) arguments // Chaining vertex methods
Person.findAll({'age': 20}).createEdge(Uses, {'frequency': 'daily'}, Website.find({'name': 'Facebook'}), (error, result) => {
// Result is array of newly created edges from everyone with age 20 to the website 'Facebook'
});
// Calling .createEdge on model instances
Person.findAll({'occupation': 'web developer'}, (error, results) => {
let developers = results;
Language.findAll({'name': ['Javascript', 'HTML', 'CSS']}, (error, results) => {
let languages = results;
developers.createEdge(Uses, {}, languages, (error, result) => {
// Result is array of newly created edge objects from each web developers
// to each of the 3 important components of web development
});
});
});
// Creating edges both ways
Person.find({'name': 'Jane'}, (error, result) => {
let jane = result;
Person.find({'name' : 'John'}).createEdge(Knows, {since: '1999'}, jane, true, (error, result) => {
// Creates two edges so that John knows Jane and Jane also knows John
})
});
.findEdge finds edges directly connected to the relevant vertex(es)
edge: Edge model. If a string label is passed, no schema check will be done - edge model is recommendedprops: Object containing key value pairs of properties to match on edge relationshipscallback (optional): Some callback function with (error, result) argumentsPerson.find({'name': 'John'}).findEdge(Knows, {'from': 'school'}, (error, result) => {
// Result is array of edge objects representing all the 'knows' relationships of John
// where John knows the person from school (edge model property)
});
.findRelated finds vertices related through the desired edge relationship.
edge: Edge model. If a string label is passed, no schema check will be done - edge model is recommended.props: Object containing key value pairs of properties to match on edge relationshipsdepth: Depth of edge traversals to makeinModel (optional, default = this): Vertex model of results to find. Can pass a vertex model (Person) or label string ('person') -- vertex model is recommended.callback (optional): Some callback function with (error, result) argumentsPerson.find({'name': 'John'}).findRelated(Knows, {}, 2, (error, result) => {
// Result is array of Person records representing John's friends of friends
});
Person.find({'name': 'John'}).findRelated(Likes, {}, 1, Movie, (error, result) => {
// Result is array of Movie records that John likes.
});
.findImplicit finds vertices that are related to another vertex the same way the original vertex is.
edge: Edge model. If a string label is passed, no schema check will be done - edge model is recommended.props: Object containing key value pairs of properties to match on edge relationshipscallback (optional): Some callback function with (error, result) argumentsPerson.find({'name': 'John'}).findImplicit('created', {}, (error, result) => {
// Result is array of vertex objects representing people who have co-created things that John created
});
.create creates an index from out vertex(es) to the in vertex(es)
out: Vertex instance(s) or find/findAll method callin: Vertex instance(s) or find/findAll method callprops: Object containing key value pairs of properties to add on the new edgeboth (optional, default = false): If true, will create edges in both directionscallback: Some callback function with (error, result) argumentsPerson.find({'name': 'Joe'}, (error, result) => {
let joe = result;
Knows.create(Person.find({'name': 'John'}), joe, {'since': 2015}, (error, result) => {
// Returns the newly created edge
/*
{
"id": "1",
"label": "knows",
"since": "2015",
"outV": "1", // John's id
"inV": "2", // Joe's id
}
*/
});
});
.find finds the first edge with properties matching props object
props: Object containing key value pairs of propertiescallback (optional): Some callback function with (error, result) arguments Knows.find({'since': 2015}, (error, result) => {
// Returns first edge found matching props
/*
{
"id": "1",
"label": "knows",
"since": 2015,
"outV": 1,
"inV": 123
}
*/
});
.findAll finds the all edges with properties matching props object
props: Object containing key value pairs of propertiescallback (optional): Some callback function with (error, result) arguments Knows.findAll({'since': 2015}, (error, result) => {
// Returns array of matching edges
/*
[
{
"id": "1",
"label": "knows",
"since": 2015,
"outV": 1,
"inV": 123
},
{
"id": "2",
"label": "knows",
"since": 2015,
"outV": 1,
"inV": 200
}
]
*/
});
.findVertex finds the all vertices with properties matching props object connected by the relevant edge(s)
vertexModel: Vertex model. If a string label is passed, no schema check will be done - vertex model is recommended.props: Object containing key value pairs of properties to find on verticescallback (optional): Some callback function with (error, result) argumentsKnows.find({'through': 'school'}).findVertex(Person, {'occupation': 'developer'}, (error, result) => {
// Result is array of people who are developers who know other people through school
});
object: Object to check equality withobject: Object to check inequality withobject: Object to check less than withobject: Object to check less than equal to withobject: Object to check greater than withobject: Object to check greater than equal to withobject1: Object to check greater than withobject2: Object to check less than withobject1: Object to check less than withobject2: Object to check greater than withobject1: Object to check greater than equal to withobject2: Object to check less than equal to withobjects: Array to have one of the valuesobjects: Array to not have the valuestr: String to start withstr: String to end withstr: String containedstr: String to not start withstr: String to not end withstr: String to not be containedkey: key to query over (an array field ideally)value: An array ideally, where the key needs to contain all the provided valuesprops: key/value to perform OR query overPerson with age greater than 35
Person.findAll({ age: Action.P_gt(35) }, (error, results) => {
if (error) {
console.error(error);
} else {
console.log(`Results: ${results.length}`);
console.log(results);
}
})
Person with both the tags 'Abc' and 'Def'
Person.findActionAll(Action.Has_And, { tags: ['Abc', 'Def'] }, (error, results) => {
if (error) {
console.error(error);
} else {
console.log(`Results: ${results.length}`);
console.log(results);
}
})
Person with name either 'Abc' or 'Def' or age is 75
Person.findActionAll(Action.Or, { name: ['Abc', 'Def'], age: 75 }, (error, results) => {
if (error) {
console.error(error);
} else {
console.log(`Results: ${results.length}`);
console.log(results);
}
})
This project is licensed under the MIT License
FAQs
Gremlin ORM for Node.js
We found that @rrnara/gremlin-orm 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.