npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

objection-hashid

v3.0.2

Published

Objection plugin to automatically obfuscate model ids using hashids!

Downloads

97

Readme

CI Version Downloads Docs Standard

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 © 2021 Jane Jeon.
This project is LGPL licensed (TL;DR: please contribute back any improvements to this library).