Skip to content

Commit

Permalink
acl checking moved to acler package
Browse files Browse the repository at this point in the history
  • Loading branch information
enniel committed Feb 15, 2018
1 parent 33cd2c2 commit 3515dff
Show file tree
Hide file tree
Showing 4 changed files with 3 additions and 231 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"author": "Evgeny Razumov (enniel)",
"license": "MIT",
"dependencies": {
"acler": "^1.0.0",
"lodash": "^4.17.4",
"node-exceptions": "^2.0.2"
},
Expand Down
115 changes: 2 additions & 113 deletions src/Acl/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,122 +7,11 @@
*/

const _ = require('lodash')
const InvalidExpression = require('../Exceptions/InvalidExpression')
const { check } = require('acler')

const Acl = exports = module.exports = {}

const operators = {
or: {
precedence: 1,
func: (a, b) => a || b
},
and: {
precedence: 2,
func: (a, b) => a && b
},
not: {
precedence: 3,
func: b => !b,
n: 1
}
}

// synonyms
operators['&&'] = operators.and
operators['||'] = operators.or
operators['!'] = operators.not

// add whitespace to '(', ')', and '!' operators so that
// "(a && !b)" -> "( a && ! b )"
const addSpaces = (string) => {
const split = string.split('')
const characters = split.map((character, i) => {
if (character === '(' || character === ')') {
if (split[i - 1] !== ' ') character = ' ' + character
if (split[i + 1] !== ' ') character = character + ' '
}
if (character === '!') {
if (split[i + 1] !== ' ' && split[i + 1] !== '=') {
character = character + ' '
}
}
return character
})
return characters.join('')
}

// Uses the shunting-yard algorithm to convert infix notation
// into Reverse Polish Notation
const convertToRPN = (exp) => {
if (typeof exp !== 'string') {
throw new InvalidExpression()
}
exp = exp
.replace(/\s+/g, ' ')
.replace(/\s+$/, '')
.replace(/^\s+/, '')
exp = addSpaces(exp)
const stack = []
const rpn = []
for (let token of exp.trim().split(' ')) {
if (operators[token]) {
// This assumes no right-associative operators
while (
stack[stack.length - 1] &&
operators[stack[stack.length - 1]] &&
operators[token].precedence <= operators[stack[stack.length - 1]].precedence) {
rpn.push(stack.pop())
}
stack.push(token)
} else if (token === '(') {
stack.push(token)
} else if (token === ')') {
while (stack.length && stack[stack.length - 1] !== '(') {
rpn.push(stack.pop())
}
if (stack[stack.length - 1] === '(') {
stack.pop()
} else {
throw new InvalidExpression()
}
} else if (/^[a-zA-Z_-]+$/.test(token)) {
rpn.push(token)
} else {
throw new InvalidExpression()
}
}
return rpn.concat(stack.reverse())
}

const toBool = (operand, checker) => {
if (typeof operand === 'boolean') {
return operand
}
return checker(operand)
}

Acl.check = (expression, checker) => {
const rpn = convertToRPN(expression)
const stack = []
for (let token of rpn) {
const operator = operators[token]
if (operator) {
const numArgs = operator.n || 2
let args = []
for (let i = 1; i <= numArgs; i++) {
const arg = toBool(stack.pop(), checker)
args.push(arg)
}
args = args.reverse()
const result = operator.func(...args)
stack.push(result)
} else {
const result = toBool(token, checker)
stack.push(result)
}
}
return stack[0]
}
Acl.check = check

Acl.validateScope = (required, provided) => {
return _.every(required, (scope) => {
Expand Down
21 changes: 0 additions & 21 deletions src/Exceptions/InvalidExpression.js

This file was deleted.

97 changes: 0 additions & 97 deletions test/unit/acl.spec.js

This file was deleted.

0 comments on commit 3515dff

Please sign in to comment.