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

stockade-hook

v1.1.0

Published

Extends sails with a modular permissions system for guarding controller actions in a cleaner way than policies. Uses the `Stockade` module as a singleton permissions store and general helper library.

Downloads

11

Readme

Stockade-hook

This hook enforces usage of the Stockade module for all Sails actions, providing automagic action patching meant to validate requests against some defined criteria. Where validation criteria are not specified for any given route, that route will always yield in a 403 Forbidden response being sent to the user, as a strict safety measure.

Reading the Stockade readme can be quite helpful and is suggested.

Features

Stockade permission validation

The primary goal of this hook is to enforce and automatically apply Stockade permission validations in a convenient way. Stockade usage is described quote thoroughly in the Stockade readme. A dedicated section exists regarding playing together with this hook.

Action parameter validation

This hook now provides not only convenient Stockade functionality, but also exposes a means of defining automatically executed validations against both Joi and Waterline schema.

Action validation definitions are defined in the same general location as your Stockade permission validations: the Sails _config object on each controller. Unlike Stockade permissions though, the presence of parameter validations is not strictly enforced and actions will work fine without them (this is a completely opt-in feature).

Simple parameter validation

Parameter validations may be defined as simple objects which will be converted to Joi object schema:

/**
 * @file UserController.js
 * Provides actions related to updating and retrieving user data.
 */

const { Joi, Permissions } = require('stockade-hook');

module.exports = {

    _config: {
        permissions: {
            getInfo: Permissions.for('user').allOf('isLoggedIn'),
        },
        validations: {
            getInfo: {
                userId: Joi.string().hex().length(24).required(),
            },
        },
    },

    async getInfo(req, res) {
        // ...
    },

};

The configuration above will ensure that the getInfo action has a parameter userId which satisfies all of:

  • is a string
  • is a hexadecimal string
  • has a length of exactly 24 characters

If any condition above could not be satisfied, the getInfo action will not be run and an error will be sent out instead (via res.badRequest(...)). If the Floatplane Errors hook is also installed, generated errors will be enriched with additional info and functionality (such as localisation, etc.).

Whenever Joi validations are executed without error, the sanitised result of this validation will be assigned to the req.validatedParams property. This allows for accessing any Joi-assigned defaults and avoiding any parameters which were stripped by Joi.

If additional control over the parameters validation schema is required, an already-constructed Joi schema may be passed just as well:

        validations: {
            getInfo: Joi.object().keys({
                userId: Joi.string().hex().length(24).required(),
            }).unknown(false),
        },

Simple parameter validation should always be preferred when possible. Some cases where it may not be possible include scenarios where either:

  1. your parameter schema includes a field named example joi or waterline; or
  2. more control is required over the source schema itself.

The limitation described by case #1 is brought about by the need for explicit/advanced validators. These are validators defined like so:

        validations: {
            getInfo: {
                joi: {
                    userId: Joi.string().hex().length(24).required(),
                },
                waterline: {
                    // ...
                },
            },
        },

If stockade-hook ever sees a joi or waterline top-level validator property, the schema is promoted to an advanced property which may contain not only Joi validations, but Waterline validations as well.

As is demonstrated above, advanced validators accept the same form of Joi schema as simple validators–the only difference is that the schema is now associated with the joi property.

Validating against Waterline model attributes

In addition to validating request parameters against Joi schema, it is also possible to perform validations against Waterline model attributes. This can be quite convenient when it's required to accept data which might be used to create or patch some model instance.

In order to validate against Waterline, we must create an advanced validator to inform stockade-hook that we'd like something beyond just simple Joi validation.

Performing validation against some Waterline model might look something like so:

/**
 * @file UserController.js
 * Provides actions related to updating and retrieving user data.
 */

const { Joi, Permissions } = require('stockade-hook');

module.exports = {

    _config: {
        permissions: {
            getInfo: Permissions.for('user').allOf('isLoggedIn'),
        },
        validations: {
            getInfo: {
                joi: {
                    username: Joi.string().required(),
                },
                waterline: {
                    username: 'User.username',
                },
            },
        },
    },

    async getInfo(req, res) {
        // ...
    },

};

The schema defined above will ensure that the username parameter fully satisfies all Sails model validations defined for the User.username attribute. If an invalid value is given, the action will not execute.

Waterline validations may be augmented with usage of either and or or functionality.

For example, to allow through a value which is either a User.username or User.email:

                waterline: {
                    usernameOrEmail: { or: ['User.username', 'User.email'] },
                },

Please note that Joi validations will always be executed prior to Waterline validations, and that these Waterline validations might be avoided altogether if the Joi validation phase fails. Additionally, Waterline validations may of course be defined without any joi block.

Advanced Joi validation control

By default, stockade-hook does not supply any extra options to the Joi validation function. As a result of this, unknown fields are forbidden, error-checking aborts early after the first error is found, and so on consistent with the Joi defaults.

If refined control over the Joi validation is required, options may be provided by assigning a tuple of form [schema, options] for any Joi schema. In this form, schema represents a Joi schema as described prior, while options represents an object to be passed to the Joi.validate call made upon validation.

An example where the early abort default is disabled:

/**
 * @file UserController.js
 * Provides actions related to updating and retrieving user data.
 */

const { Joi, Permissions } = require('stockade-hook');

module.exports = {

    _config: {
        permissions: {
            getInfo: Permissions.for('user').allOf('isLoggedIn'),
        },
        validations: {
            getInfo: {
                joi: [{
                    // The usual Joi schema goes here at [0].
                    username: Joi.string().required(),
                    include: Joi.array().items(
                        Joi.string().only('playlists', 'subscriptions'),
                    ),
                }, {
                    // Joi.validate options go here at [1].
                    abortEarly: false,
                }],
            },
        },
    },

    async getInfo(req, res) {
        // ...
    },

};