urn-schema

URN schema validation

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
urn-schema
0.2.18 years ago8 years agoMinified + gzip package size for urn-schema in KB

Readme

URN Schema
This library handles URN schemas, similar to AWS ARN's, useful for access control.
Features:
  • x Variable interpolation urn:${some.dataset}
  • x Wildcarding urn:*
  • x Precompilation for performance
  • x Uri validation urn:this/${is.a}/*/uri?with&a&query
  • x ACL's
  • x 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