All Projects → JaneJeon → objection-hashid

JaneJeon / objection-hashid

Licence: LGPL-3.0 license
Objection plugin to automatically obfuscate model ids using hashids!

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to objection-hashid

id-mask
IDMask is a Java library for masking internal ids (e.g. from your DB) when they need to be published to hide their actual value and to prevent forging. It has support optional randomisation has a wide support for various Java types including long, UUID and BigInteger. This library bases its security on strong cryptographic primitives.
Stars: ✭ 39 (+200%)
Mutual labels:  hashids, hashid
nestjs-objection
Objection module for NestJS
Stars: ✭ 24 (+84.62%)
Mutual labels:  objectionjs, objection
laravel-hashid
HashId Implementation on Laravel Eloquent ORM
Stars: ✭ 23 (+76.92%)
Mutual labels:  hashids, hashid
typescript-api-starter
🔰 Starter for Node.js express API in Typescript 🚀
Stars: ✭ 72 (+453.85%)
Mutual labels:  objectionjs, objection
objection-authorize
isomorphic, "magical" authorization integration with Objection.js 🎉
Stars: ✭ 71 (+446.15%)
Mutual labels:  objectionjs, objection
Pg hashids
Short unique id generator for PostgreSQL, using hashids
Stars: ✭ 164 (+1161.54%)
Mutual labels:  hashids
hashids.sql
PL/pgSQL implementation of hashids library
Stars: ✭ 40 (+207.69%)
Mutual labels:  hashids
Laravel Hashslug
Package providing a trait to use Hashids on a model
Stars: ✭ 136 (+946.15%)
Mutual labels:  hashids
Laravel Optimus
Transform your internal id's to obfuscated integers based on Knuth's integer hash. Laravel wrapper for the Optimus Library by Jens Segers with multiple connections support.
Stars: ✭ 119 (+815.38%)
Mutual labels:  hashids
contentjet-api
Headless API-first content management system
Stars: ✭ 95 (+630.77%)
Mutual labels:  objectionjs
express-objection-starter
an opinionated, production-ready, isomorphic express/knex/objection starter with centralized configuration
Stars: ✭ 19 (+46.15%)
Mutual labels:  objection
django-hashids
Non-intrusive hashids library for Django
Stars: ✭ 26 (+100%)
Mutual labels:  hashids
Hashids.github.io
Hashids website
Stars: ✭ 163 (+1153.85%)
Mutual labels:  hashids
Laravel Fakeid
Automatic model ID obfuscation in routes for Laravel
Stars: ✭ 161 (+1138.46%)
Mutual labels:  hashids
hashids.pm
Hashids, ported for Perl
Stars: ✭ 15 (+15.38%)
Mutual labels:  hashids
Laravel Hashids
A Hashids bridge for Laravel
Stars: ✭ 1,714 (+13084.62%)
Mutual labels:  hashids
laravel-hashids
Laravel package for Hashids
Stars: ✭ 52 (+300%)
Mutual labels:  hashids
hashids-erlang
The Erlang port of Hashid to generate YouTube-like hashids from one or many numbers.
Stars: ✭ 19 (+46.15%)
Mutual labels:  hashid
Hashid Rails
Use Hashids (http://hashids.org/ruby/) in your Rails app ActiveRecord models.
Stars: ✭ 225 (+1630.77%)
Mutual labels:  hashids
graphql-example
GraphQL Sample Project
Stars: ✭ 32 (+146.15%)
Mutual labels:  objectionjs

Welcome to objection-hashid 👋

CircleCI codecov Version Downloads Docs

Objection plugin to automatically obfuscate model ids using hashids!

🏠 Homepage

Enjoy objection-hashid? Check out my other objection plugins: objection-authorize and objection-tablename!

Why?

Sometimes you don't want to expose the id's of your model directly. Instead of {id: 1}, you can have {id: 'W02nmXZ'} like YouTube's video id or bitly's link id.

That's where hashids and this plugin comes in: it automatically converts the model id(s) (yes, it supports compound PKs) into an obfuscated form for the outside world to read, and then convert it back to the original form when the server's trying to read the model id.

And all of this operation is entirely isomorphic, so you don't have to worry about the integrity of the ids and id references as you convert back and forth between your auto-generated id and the hashed version!

Install

yarn add objection-hashid # or
npm install objection-hashid --save

Usage

const { Model } = require('objection')
const hashid = require('objection-hashid')

class Post extends hashid(Model) {
  // that's it! This is just a regular objection.js model class
}

Then you can take your resource model and...

const post = await Post.query().findById(42)
console.log(post.id) // 42
console.log(post.hashId) // some string "XYZ"
console.log(JSON.stringify(post)) // {id: "XYZ", ...}

Note that the hashed form of your model id is readable while it's an object (i.e. you haven't serialized it yet by sending it thru res.send(), for example) via the hashId property.

When serialized, the hashId property won't be written so that your resulting object stays clean. Instead, the hashId gets written into the id field, overwriting it (this is configurable; see the Configuration section).

Now when you receive an object that has an encoded hashid, you can "decode" it and find the model using the findByHashId query:

console.log(obj.id) // "XYZ"

const post = await Post.query().findByHashId(obj.id)
console.log(post.id) // 42
console.log(post.hashId) // "XYZ"

Additionally, this plugin automatically detects and adjusts for composite primary keys, so you don't have to do anything; the hashid will show up the same:

class SomeModel extends hashid(Model) {
  static get idColumn() {
    return ['id1', 'id2']
  }
}

const model = await SomeModel.query().findById([1, 2])
console.log(model.$id()) // [1, 2]
console.log(model.hashId) // "XYZ"
console.log(JSON.stringify(model)) // {id1: 1, id2: 2, id: "XYZ"}

const obj = await SomeModel.query().findByHashId(model.hashId)
assert(obj.$id() == model.$id())

You can even use this plugin with objection-visibility:

const { Model } = require('objection')
const visibility = require('objection-visibility').default
const hashid = require('objection-hashid')

class BaseModel extends hashid(visibility(Model)) {
  static get hidden() {
    return ['foo', 'bar']
  }
}

It's recommended that you apply this plugin AFTER objection-visibility since the order in which you apply the plugins affect how properties are handled.
Specifically, applying the visibility plugin after this plugin might strip away the hashid from the serialized object.

Note that this plugin directly uses Objection hooks to provide its functionality, so you don't have to do change your code if you're already using virtualAttributes.

And finally, you can hash non-id fields as well (especially useful for hashing foreign key references). For example, if you have a Post model that has a creatorId that points to a User's id, you can hash the creatorId field as well as the id field.

In fact, you can hash any arbitrary non-id field in the model as follows:

class Post extends hashid(Model) {
  static get hashedFields() {
    return ['creatorId'] // specify any non-PK fields
  }
}

Configuration

You might've noticed that when initializing this plugin, it doesn't take in any options object. Instead, all of the configuration is done through specifying model properties, meaning you can configure this plugin on a per-model basis!

The hashids library accepts up to four parameters (see hashids.org for more details): salt, minLength, alphabet, and seps.

Each of those properties, for each model, can be overwritten by setting them as static properties. For example, if you want your hashid's to be at least 5 characters long:

class BaseModel extends hashid(Model) {
  static get hashIdMinLength() {
    return 5
  }
}

So the hashid parameters can be overwritten by static hashIdSalt, hashIdMinLength, hashIdAlphabet, and hashIdSeps properties.

Furthermore, the hashIdSalt property defaults to the model's class name, i.e. your generated hashid's won't "collide" between two different models!

To configure which field the hashid is written to during serialization, set the static hashIdField property.
By default, it's id, but you can change it to any string (e.g. hashid), or, you can set it to a falsey value to disable writing the hashid to the final object, meaning you can only access the hashid before it's serialized.

Configuring for Foreign Key Relations

Note that if you have any models that point to each other, every bit of configuration that deals with the generation of hashids MUST be the same.

This usually just means passing the same hashIdSalt to both models (if you haven't configured any other fields differently) since hashIdSalt varies based on the model's name.

If you have a lot of models pointing to each other, though, I recommend that you have a BaseClass with the appropriate hashId configuration and just subclass all your models off of it, not touching any of the hashId configurations at the individual model level.

Run tests

yarn test

Author

👤 Jane Jeon

🤝 Contributing

Contributions, issues and feature requests are welcome!
Feel free to check the issues page.

Show your support

Give a ⭐️ if this project helped you!

📝 License

Copyright © 2022 Jane Jeon.
This project is LGPL licensed.

TL;DR: you are free to import and use this library "as-is" in your code, without needing to make your code source-available or to license it under the same license as this library; however, if you do change this library and you distribute it (directly or as part of your code consuming this library), please do contribute back any improvements for this library and this library alone.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].