@scispike/domain-object-security

1.0.0-rc.2 • Public • Published

domain-object-security

This library allows you to secure your domain objects, so that you can ask questions like "Can Sally read Bob's account balance?" or "Can bank teller Jan close account #123?"

DEPRECATION NOTE: Since the time this package was created, SciSpike has been acquired by Northscaler. There will be no further development on this module. Instead, development will continue at either @northscaler/method-access-controller for functionality related to RoleTypeBasedObjectAccessControlRepository, which has been rename there to MethodAccessController, or @northscaler-public/securable-trait for Securable. You can see all of Northscaler's public Node.js modules at https://www.npmjs.com/search?q=%40northscaler.

The primary export of this module is a trait called Securable, which you can cause your class(es) to express; see our mutrait package for full trait support in JavaScript.

TL;DR

File Account.js:

const { traits } = require('mutrait')
const { Securable } = require('@scispike/domain-object-security')

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

TIP: When you combine this library with method interception via @scispike/aspectify and with ClsHookedContext or ZoneJsContext from @scispike/nodejs-support, you can completely isolate the crosscutting concern of security.

File Secured.js:

const { Before } = require('@scispike/aspectify')
const Context = require('@scispike/nodejs-support/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('mutrait')
const { Securable } = require('@scispike/domain-object-security')
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 in src/test/unit/Securable.spec.js for usage.

Package Sidebar

Install

npm i @scispike/domain-object-security

Weekly Downloads

0

Version

1.0.0-rc.2

License

MIT

Unpacked Size

39.4 kB

Total Files

7

Last publish

Collaborators

  • npm_scispike