0.2.1 • Published 10 years ago

urn-schema v0.2.1

Weekly downloads
415
License
-
Repository
-
Last release
10 years ago

URN Schema

This library handles URN schemas, similar to AWS ARN's, useful for access control.

Features:

  • Variable interpolation urn:${some.dataset}
  • Wildcarding urn:*
  • Precompilation for performance
  • Uri validation urn:this/${is.a}/*/uri?with&a&query
  • ACL's
  • Conforms to URN
import UrnSchema, { UriValidator } from 'urn-schema'

const schema = new UrnSchema('version:method:scope:uri', {
    uri: UriValidator,
})

const acl = schema.createAcl({
    group_a: [
        "urn:1.0:POST:testing:products/*/items/*"
    ]
})

acl.validate('group_a', {
    version : '1.0',
    method  : 'POST',
    scope   : 'testing',
    uri     : 'products/22/items'
}) // returns { valid: true, group: 'group_a' }

acl.validate('group_a', {
    version : '2.0',
    method  : 'GET',
    scope   : 'testing',
    uri     : 'products/22/items'
}) // returns { valid: false, group: 'group_a' }

In the basic example above we have defined a schema which matches predefined properties, including parsing the uri appropriately.

Below is a more advanced example.

const acl = schema.createAcl({
    group_a: [
        "urn:${versions}:GET:${scopes}:products/${user['!~validIds~!']}/*?direction&order"
    ]
})

const data = {
    versions: [ '1.0', '2.0' ],
    scopes: [ 'testing', 'staging' ],
    user: {
        "!~validIds~!": [ 22, 24, 77 ]
    }
}

acl.validate('group_a', {
    version : '2.0',
    method  : 'GET',
    scope   : 'testing',
    uri     : 'products/22/items?order=size'
}, data) // returns { valid: true, group: 'group_a' }

In the above example the variables defined in group_a's first urn are interpolated from the data object.

These uri's would also pass:

  • products/24/
  • products/27/something?direction=asc

And so too would version 1.0 and scope staging.

It's easy to parse a full URL into something you can use against the schema. Imagine the below originalUrl is /2.0/testing/products/22.

app.use((req, res, next) => {
    const { method, originalUrl, auth } = req

    // Take off the first 2 parts
    let [ version, scope, ...uri ] = originalUrl
        .replace(/^\/|\/$/g, '') // Remove trailing & leading slashes
        .split('/')

    uri = uri.join('/') // Join it back up

    const aclCheck = acl.validate(auth.scope, {
        version, scope, method, uri
    })

    if ( aclCheck.valid )
        return next()

    return next( new ForbiddenError("Permission denied!!!") )
})

Interpolation Mechanics

When a variable is interpolated, the type matters.

  • If ${some.data} resolves to an array [1, 2], then the value can match either of them, as a string comparison
  • If ${some.data} resolves to any other type, it will be stringified and compared against the value
0.2.1

10 years ago

0.2.0

10 years ago

0.1.2

10 years ago

0.1.1

10 years ago

0.1.0

10 years ago