Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Nohm is an object relational mapper (ORM) written for node.js and redis written in Typescript.
The examples/rest-user-server is running as a demo on https://nohm-example.maritz.space. It showcases most features on a basic level, including the shared validation and PubSub.
import { Nohm, NohmModel, ValidationError } from 'nohm';
// or if your environment does not support module import
// const NohmModule = require('nohm'); // access NohmModule.Nohm, NohmModule.NohmModel and NohmModule.ValidationError
// This is the parent object where you set redis connection, create your models and some other configuration stuff
const nohm = Nohm;
nohm.setPrefix('example'); // This prefixes all redis keys. By default the prefix is "nohm", you probably want to change it to your applications name or something similar
// This is a class that you can extend to create nohm models. Not needed when using nohm.model()
const Model = NohmModel;
const existingCountries = ['Narnia', 'Gondor', 'Tatooine'];
// Using ES6 classes here, but you could also use the old nohm.model definition
class UserModel extends Model {
getCountryFlag() {
return `http://example.com/flag_${this.property('country')}.png`;
}
}
// Define the required static properties
UserModel.modelName = 'User';
UserModel.definitions = {
email: {
type: 'string',
unique: true,
validations: ['email'],
},
country: {
type: 'string',
defaultValue: 'Narnia',
index: true,
validations: [
// the function name will be part of the validation error messages, so for this it would be "custom_checkCountryExists"
async function checkCountryExists(value) {
// needs to return a promise that resolves to a bool - async functions take care of the promise part
return existingCountries.includes(value);
},
{
name: 'length',
options: { min: 3 },
},
],
},
visits: {
type: function incrVisitsBy(value, key, old) {
// arguments are always string here since they come from redis.
// in behaviors (type functions) you are responsible for making sure they return in the type you want them to be.
return parseInt(old, 10) + parseInt(value, 10);
},
defaultValue: 0,
index: true,
},
};
// register our model in nohm and returns the resulting Class, do not use the UserModel directly!
const UserModelClass = nohm.register(UserModel);
const redis = require('redis').createClient();
// wait for redis to connect, otherwise we might try to write to a non-existent redis server
redis.on('connect', async () => {
nohm.setClient(redis);
// factory returns a promise, resolving to a fresh instance (or a loaded one if id is provided, see below)
const user = await nohm.factory('User');
// set some properties
user.property({
email: 'mark13@example.com',
country: 'Gondor',
visits: 1,
});
try {
await user.save();
} catch (err) {
if (err instanceof ValidationError) {
// validation failed
for (const key in err.errors) {
const failures = err.errors[key].join(`', '`);
console.log(
`Validation of property '${key}' failed in these validators: '${failures}'.`,
);
// in a real app you'd probably do something with the validation errors (like make an object for the client)
// and then return or rethrow some other error
}
}
// rethrow because we didn't recover from the error.
throw err;
}
console.log(`Saved user with id ${user.id}`);
const id = user.id;
// somewhere else we could then load the user again
const loadedUser = await UserModelClass.load(id); // this will throw an error if the user cannot be found
// alternatively you can use nohm.factory('User', id)
console.log(`User loaded. His properties are %j`, loadedUser.allProperties());
const newVisits = loadedUser.property('visits', 20);
console.log(`User visits set to ${newVisits}.`); // Spoiler: it's 21
// or find users by country
const gondorians = await UserModelClass.findAndLoad({
country: 'Gondor',
});
console.log(
`Here are all users from Gondor: %j`,
gondorians.map((u) => u.property('email')),
);
await loadedUser.remove();
console.log(`User deleted from database.`);
});
import { Nohm, NohmModel, TTypedDefinitions } from 'nohm';
// We're gonna assume the basics are clear and the connection is set up etc. - look at the ES6 example otherwise.
// This example highlights some of the typing capabilities in nohm.
interface IUserProperties {
email: string;
visits: number;
}
class UserModel extends NohmModel<IUserProperties> {
public static modelName = 'User';
protected static definitions: TTypedDefinitions<IUserProperties> = {
// because of the TTypedDefinitions we can only define properties keys here that match our interface keys
// the structure of the definitions is also typed
email: {
type: 'string', // the type value is currently not checked. If you put a wrong type here, no compile error will appear.
unique: true,
validations: ['email'],
},
visits: {
defaultValue: 0,
index: true,
type: function incrVisitsBy(value, _key, old): number {
return old + value; // TS Error: arguments are all strings, not assignable to number
},
},
};
public getVisitsAsString(): string {
return this.property('visits'); // TS Error: visits is number and thus not assignable to string
}
public static async loadTyped(id: string): Promise<UserModel> {
// see main() below for explanation
return userModelStatic.load<UserModel>(id);
}
}
const userModelStatic = nohm.register(UserModel);
async function main() {
// currently you still have to pass the generic if you want typing for class methods
const user = await userModelStatic.load<UserModel>('some id');
// you can use the above defined loadTyped method to work around that.
const props = user.allProperties();
props.email; // string
props.id; // any
props.visits; // number
props.foo; // TS Error: Property foo does not exist
user.getVisitsAsString(); // string
}
main();
Do you have code that should/could be listed here? Message me!
npm install --save nohm
Nohm uses the debug module under the namespace "nohm". To see detailed debug logging set the environment variable DEBUG accordingly:
DEBUG="nohm:*" node yourApp.js
Available submodule debug namespaces are nohm:index
, nohm:model
, nohm:middleware
, nohm:pubSub
and nohm:idGenerator
.
If you want to make changes to nohm, you can fork or clone it. Then install the dependencies:
npm install
and run the development scripts (compile & watch & tests):
npm run dev
When submitting PRs, please make sure that you run the linter and that everything still builds fine.
The easiest way to do that is to run the prepublishOnly
script:
npm run prepublishOnly
Build the javascript files:
npm run build
Then run the tests:
npm run test
# or
npm run test:watch
This requires a running redis server. (you can configure host/port with the command line arguments --redis-host 1.1.1.1 --redis-port 1234)
WARNING: The tests also create a lot of temporary keys in your database that look something like this:
nohmtestsuniques:something:something
After the tests have run all keys that match the pattern nohmtests* are deleted!
You can change the prefix ("nohmtests") part doing something like
node test/tests.js --nohm-prefix YourNewPrefix
Now the keys will look like this:
YourNewPrefixuniques:something:something
FAQs
redis ORM (Object relational mapper)
We found that yinohm 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
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.