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

access-manager

v1.1.3

Published

A one-stop solution for implementing authenticated and anonymous continuous sessions with user handling and whitelisted acl.

Downloads

15

Readme

access-manager

© WeeHorse 2018, MIT license

Authentication, Sessions and ACL

Access Manager is a one-stop solution for implementing authenticated and anonymous sessions with user handling and whitelisted ACL. Keeps the same session regardless of authenticated state. Attaches itself to an express app as a middleware.

Install

$ npm install access-manager

Install ACL data

If you want some example data or wish to import your ACL from file, use the --import-acl switch when you start your app with access manager (for the first time). Note that your app will shut down once the import is done.

Use example data: (see below)

$ node app --import-acl

Or provide your own file:

$ node app --import-acl=file.json

The ACL data installs into the acl collection. Obviously you're free to populate the acl collection anyway you see fit.

The example ACL data:

[
  {"path":"/rest/admin*", "roles":[ {"role": "admin", "methods": ["ALL"]}, {"role": "super", "methods": ["ALL"]} ]},
  {"path":"/rest/login", "roles":[ {"role": "anonymous", "methods": ["POST"]} ]},
  {"path":"/rest/logout", "roles":[ {"role": "user", "methods": ["GET","POST"]} ]},
  {"path":"/rest/news*", "roles":[ {"role": "*", "methods": ["GET"]} ]},
  {"path":"/rest/messages*", "roles":[ {"role": "user", "methods": ["GET","POST","DELETE"]} ]},
  {"path":"/rest/user", "roles":[ {"role": "user", "methods": ["GET"]} ]},
  {"path":"/rest/register", "roles":[ {"role": "anonymous", "methods": ["POST"]}, {"role": "super", "methods": ["POST"]} ]}
]

It works like this: Only the paths detailed above are valid paths together with the correct user role and method, all other paths will be blocked with 403 Forbidden. You may end any path with a wildcard *, letting traffic through on all subpaths.

Examples of access-manager usage:

Typical init with basic dependencies

const express = require('express');
const app = express();
const bodyParser = require('body-parser');

const bcrypt = require('bcrypt');
const saltRounds = 10;

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/some_database');

// IMPORTANT - if you don't want to block frontend files with access-manager, serve them before access-manager:
app.use(express.static('../client/'));

const AccessManager = require('access-manager');
const accessManager = new AccessManager({
  mongoose: mongoose, // mongoose (connected)
  expressApp: app // an express app
});

Configuration

You can optionally add your own schemas (Schema Objects) for users, sessions and acl, at the properties: userSchema, sessionSchema, aclSchema

Some properties in the schemas are required by the access-manager. Those details can be found at the bottom of this document.

You will propably want to supply your own userSchema, an example of doing that:

const accessManager = new AccessManager({
  mongoose: mongoose,
  expressApp: app,
  userSchema: {
    firstName: {type: String, required:true},
    lastName: {type: String, required:true},
    email: {type: String, required:true, unique:true}, // required access manager property
    password: {type: String, required:true}, // required access manager property
    roles: [String]  // required access manager property
  }

The models access manager uses are then avaliable from access manager:

const User = accessManager.models.user;

Now access manager will do its work seamlessly in the background, but we need a user, so here's a registration route:

The example ACL will only allow anonymous users and super users create accounts

app.post('/rest/register', async (req, res)=>{
  // encrypt password
  req.body.password = await bcrypt.hash(req.body.password, saltRounds);
  // create user
  let user = await new User(req.body);
  await user.save();
  res.json({msg:'Registered'});
});

And login:

The example ACL will prevent this route if you are already logged in

app.post('/rest/login', async (req, res)=>{
  // find user
  let user = await User.findOne({email: req.body.email});
  // passwords match?
  if(user && await bcrypt.compare(req.body.password, user.password)){
    req.session.user = user._id;
    req.session.loggedIn = true;
    await req.session.save(); // save the state
    res.json({msg:'Logged in'});
  }else{
    res.json({msg:'Failed login'});
  }
});

To logout:

The example ACL will prevent this route if you are already logged out

app.all('/rest/logout', async (req, res)=>{
  req.user = {}; // we clear the user
  req.session.loggedIn = false; // but we retain the session with a logged out state, since this is better for tracking, pratical and security reasons
  await req.session.save(); // save the state
  res.json({msg:'Logged out'});
});

A restricted example route:

The example ACL will only allow this route on logged in users

app.get('/rest/messages', async (req, res)=>{
  res.json({msg:'Here are your messages'});
});

The current user route:

The example ACL will only allow this route on logged in users

app.get('/rest/user', (req, res)=>{
  // check if there is a logged-in user and return that user
  let response;
  if(req.user._id){
    response = req.user; // reply with the user object
    response.password = '******'; // but do not send the password back
  }else{
    response = {message: 'Not logged in'};
  }
  res.json(response);
});

Wildcard route (that takes any method) so we can test that the ACL blocks anything not allowed):

app.all('*', (req, res)=>{
  res.json({params: req.params, body: req.body}); // just echo whatever we send
});

Don't forget...

app.listen(3000,()=>{
  console.log("Remember Mystery science theatre 3000!");
});

Access manager schemas requirements

The schemas used in access manager must contain the properties detailed below. If you don't supply your own schemas these are the defaults:

The mininum required userSchema:

    {
      email: {type: String, required:true, unique:true},
      password: {type: String, required:true},
      roles: [String]
    }

The mininum required sessionSchema:

    {
      loggedIn: {type:Boolean, default:false},
      user: { type: this.mongoose.Schema.Types.ObjectId, ref: 'User' }
    }

The mininum required aclSchema:

    {
      path: {type: String, unique: true},
      roles: [
        new this.mongoose.Schema({
          role: String,
          methods: [{type: String, enum: ['GET', 'POST', 'PUT', 'DELETE', 'ALL', '*']}]
        })
      ]
    }