@northscaler/securable-trait

1.0.1 • Public • Published

securable-trait

This trait allows an object to secure itself, so that you can ask questions like "Can Sally read Bob's account balance?" or "Can bank teller John close account #123?"

The primary export of this module is a trait called Securable, which you can have your class(es) express. See our @northscaler/mutrait package for more information, including full trait support in JavaScript.

TL;DR

File Account.js:

const { traits } = require('@northscaler/mutrait')
const { Securable } = require('@northscaler/securable-trait')

class Account extends traits(Securable) {
  constructor (balance = 0, openedAt = new Date()) {
    super(balance, openedAt)
    this._balance = balance
    this.openedAt = openedAt
    this.closedAt = null
  }

  get balance () { return this._balance }
  deposit (amount) { this._balance += amount } 
  withdraw (amount) { this._balance -= amount }
  close (at = new Date()) { this.closedAt = at }
  get open () { return !this.closed }
  get closed () { return !!this.closedAt }
}

module.exports = Account

File index.js:

const Account = require('./Account')

const sally = 'sally'
const keith = 'keith'
const acct = new Account()

console.log(acct.secured) // false
console.log(acct.grants({ principals: sally, actions: 'get balance' })) // true
console.log(acct.grants({ principals: sally, actions: 'close' }))       // true
console.log(acct.grants({ principals: keith, actions: 'get balance' })) // true
console.log(acct.grants({ principals: keith, actions: 'close' }))       // true

acct.grant({ principal: sally, action: 'get balance' })
acct.grant({ principal: sally, action: 'close' })

console.log(acct.secured) // true

console.log(acct.grants({ principals: sally, actions: 'get balance' })) // true
console.log(acct.grants({ principals: keith, actions: 'close' }))       // false
console.log(acct.grants({ principals: sally, actions: 'get balance' })) // true
console.log(acct.grants({ principals: keith, actions: 'close' }))       // false

Security via aspect-oriented programming (AOP)

When you combine this library with method interception via @northscaler/aspectify and with ClsHookedContext or ZoneJsContext from @northscaler/continuation-local-storage, you can completely isolate the crosscutting concern of security.

File Secured.js:

const { Before } = require('@northscaler/aspectify')
const Context = require('@northscaler/continuation-local-storage/context/ClsHookedContext')

const secured = Before(({ thisJoinPoint }) => {
  if (!thisJoinPoint.thiz || thisJoinPoint?.thiz === thisJoinPoint?.clazz) {
    return // because we're in a static context or there's no securable to call securable.grants on
  }
    
  const token = Context().get('token')

  if (!thisJoinPoint.thiz.grants({
    principals: token.principal,
    actions: thisJoinPoint.fullName
  })) {
    const e = new Error(`E_UNAUTHORIZED`)
    e.principal = token.principal
    e.clazz = thisJoinPoint.clazz.constructor.name
    e.method = thisJoinPoint.fullName
    
    throw e
  }
})

module.exports = secured

File Account.js:

const { traits } = require('@northscaler/mutrait')
const { Securable } = require('@northscaler/securable-trait')
const secured = require('./secured')

class Account extends traits(Securable) {
  constructor (balance = 0, openedAt = new Date()) {
    super(balance, openedAt)
    this._balance = balance
    this.openedAt = openedAt
    this.closedAt = null
  }

  @secured
  get balance () { return this._balance }

  @secured
  deposit (amount) { this._balance += amount } 

  @secured
  withdraw (amount) { this._balance -= amount }

  @secured
  close (at = new Date()) { this.closedAt = at }

  @secured
  get open () { return !this.closed }

  @secured
  get closed () { return !!this.closedAt }
}

module.exports = Account

TODO

There's more to write here, but for now, see the tests for usage.

Package Sidebar

Install

npm i @northscaler/securable-trait

Weekly Downloads

1

Version

1.0.1

License

MIT

Unpacked Size

1.6 MB

Total Files

44

Last publish

Collaborators

  • ballista-admin
  • npm_northscaler
  • npm_scispike
  • victorynap