Implement command permissions

This commit is contained in:
Juan Cruz Viotti 2014-11-27 10:06:11 -04:00
parent 507ff16050
commit 5e3d973725
10 changed files with 62 additions and 41 deletions

View File

@ -1,9 +1,8 @@
_ = require('lodash')
async = require('async')
resin = require('../resin')
authHooks = require('../hooks/auth')
exports.create = authHooks.failIfNotLoggedIn (name, program) ->
exports.create = (name, program) ->
async.waterfall [
(callback) ->
@ -25,7 +24,7 @@ exports.create = authHooks.failIfNotLoggedIn (name, program) ->
], resin.errors.handle
exports.list = authHooks.failIfNotLoggedIn ->
exports.list = ->
resin.models.application.getAll (error, applications) ->
resin.errors.handle(error) if error?
@ -38,7 +37,7 @@ exports.list = authHooks.failIfNotLoggedIn ->
return application
, [ 'ID', 'Name', 'Device Type', 'Online Devices', 'All Devices' ]
exports.info = authHooks.failIfNotLoggedIn (id) ->
exports.info = (id) ->
resin.models.application.get id, (error, application) ->
resin.errors.handle(error) if error?
@ -48,12 +47,12 @@ exports.info = authHooks.failIfNotLoggedIn (id) ->
return application
, [ 'ID', 'Name', 'Device Type', 'Git Repository', 'Commit' ]
exports.restart = authHooks.failIfNotLoggedIn (id) ->
exports.restart = (id) ->
resin.models.application.restart id, (error) ->
resin.errors.handle(error) if error?
exports.remove = authHooks.failIfNotLoggedIn (id, program) ->
exports.remove = (id, program) ->
resin.ui.patterns.remove 'application', program.parent.yes, (callback) ->
resin.models.application.remove(id, callback)
, resin.errors.handle

View File

@ -1,7 +1,6 @@
open = require('open')
async = require('async')
resin = require('../resin')
authHooks = require('../hooks/auth')
exports.login = (credentials) ->
async.waterfall [
@ -17,7 +16,7 @@ exports.login = (credentials) ->
], resin.errors.handle
exports.logout = authHooks.failIfNotLoggedIn ->
exports.logout = ->
resin.auth.logout()
exports.signup = ->

View File

@ -1,7 +1,6 @@
resin = require('../resin')
authHooks = require('../hooks/auth')
exports.list = authHooks.failIfNotLoggedIn (applicationId) ->
exports.list = (applicationId) ->
resin.models.device.getAll applicationId, (error, devices) ->
resin.errors.handle(error) if error?
@ -15,11 +14,11 @@ exports.list = authHooks.failIfNotLoggedIn (applicationId) ->
return device
, [ 'ID', 'Name', 'Device Type', 'Is Online', 'IP Address', 'Application', 'Status', 'Last Seen' ]
exports.remove = authHooks.failIfNotLoggedIn (id, program) ->
exports.remove = (id, program) ->
resin.ui.patterns.remove 'device', program.parent.yes, (callback) ->
resin.models.device.remove(id, callback)
, resin.errors.handle
exports.identify = authHooks.failIfNotLoggedIn (uuid) ->
exports.identify = (uuid) ->
resin.models.device.identify uuid, (error) ->
resin.errors.handle(error) if error?

View File

@ -1,13 +1,12 @@
_ = require('lodash')
resin = require('../resin')
authHooks = require('../hooks/auth')
SYSTEM_VAR_REGEX = /^RESIN_/
isSystemVariable = (environmentVariable) ->
SYSTEM_VAR_REGEX.test(environmentVariable.name)
exports.list = authHooks.failIfNotLoggedIn (program) ->
exports.list = (program) ->
applicationId = program.parent?.application
if not applicationId?
@ -21,7 +20,7 @@ exports.list = authHooks.failIfNotLoggedIn (program) ->
resin.log.out(resin.ui.widgets.table.horizontal(environmentVariables))
exports.remove = authHooks.failIfNotLoggedIn (id, program) ->
exports.remove = (id, program) ->
resin.ui.patterns.remove 'environment variable', program.parent.yes, (callback) ->
resin.models.environmentVariables.remove(id, callback)
, resin.errors.handle

View File

@ -1,9 +1,8 @@
_ = require('lodash')
resin = require('../resin')
authHooks = require('../hooks/auth')
helpers = require('../helpers/helpers')
exports.list = authHooks.failIfNotLoggedIn ->
exports.list = ->
resin.server.get resin.config.urls.keys, (error, response, keys) ->
resin.errors.handle(error) if error?
resin.log.out resin.ui.widgets.table.horizontal keys, (key) ->
@ -11,7 +10,7 @@ exports.list = authHooks.failIfNotLoggedIn ->
return key
, [ 'ID', 'Title' ]
exports.info = authHooks.failIfNotLoggedIn (id) ->
exports.info = (id) ->
id = _.parseInt(id)
# TODO: We don't have a way to query a single ssh key yet.
@ -26,7 +25,7 @@ exports.info = authHooks.failIfNotLoggedIn (id) ->
key.public_key = '\n' + helpers.formatLongString(key.public_key, resin.config.sshKeyWidth)
resin.log.out(resin.ui.widgets.table.vertical(key, _.identity, [ 'ID', 'Title', 'Public Key' ]))
exports.remove = authHooks.failIfNotLoggedIn (id, program) ->
exports.remove = (id, program) ->
resin.ui.patterns.remove 'key', program.parent.yes, (callback) ->
resin.server.delete("/user/keys/#{id}", callback)
, resin.errors.handle

View File

@ -1,5 +1,5 @@
open = require('open')
authHooks = require('../hooks/auth')
resin = require('../resin')
exports.preferences = authHooks.failIfNotLoggedIn ->
exports.preferences = ->
open(resin.config.urls.preferences)

View File

@ -39,6 +39,7 @@ resin.cli.addCommand
command: 'logout'
description: 'logout from resin.io'
action: actions.auth.logout
permission: 'user'
resin.cli.addCommand
command: 'signup'
@ -50,40 +51,47 @@ resin.cli.addResource
name: 'app'
displayName: 'application'
actions: actions.app
permission: 'user'
resin.cli.addCommand
command: 'app:restart <id>'
description: 'restart an application'
action: actions.app.restart
permission: 'user'
# ---------- Device Module ----------
resin.cli.addResource
name: 'device'
displayName: 'device'
actions: actions.device
permission: 'user'
resin.cli.addCommand
command: 'device:identify <uuid>'
description: 'identify a device with a UUID'
action: actions.device.identify
permission: 'user'
# ---------- Preferences Module ----------
resin.cli.addCommand
command: 'preferences'
description: 'open preferences form'
action: actions.preferences.preferences
permission: 'user'
# ---------- Keys Module ----------
resin.cli.addResource
name: 'key'
displayName: 'ssh key'
actions: actions.keys
permission: 'user'
# ---------- Env Module ----------
resin.cli.addResource
name: 'env'
displayName: 'environment variable'
actions: actions.env
permission: 'user'
resin.data.prefix.set resin.config.dataPrefix, (error) ->
resin.errors.handle(error) if error?

View File

@ -1,10 +1,9 @@
_ = require('lodash')
resin = require('../resin')
auth = require('../auth/auth')
exports.failIfNotLoggedIn = (fn, onError) ->
exports.user = (fn, onError) ->
return ->
args = arguments
resin.auth.isLoggedIn (isLoggedIn) ->
auth.isLoggedIn (isLoggedIn) ->
if not isLoggedIn
error = new Error('You have to log in')

View File

@ -2,14 +2,16 @@ _ = require('lodash')
nock = require('nock')
sinon = require('sinon')
expect = require('chai').expect
resin = require('../resin')
authHooks = require('./auth')
johnDoeFixture = require('../../tests/fixtures/johndoe')
mock = require('../../tests/utils/mock')
data = require('../data/data')
auth = require('../auth/auth')
config = require('../config')
cliPermissions = require('./cli-permissions')
johnDoeFixture = require('../../../tests/fixtures/johndoe')
mock = require('../../../tests/utils/mock')
describe 'Auth Hooks:', ->
describe 'CLI Permissions:', ->
describe '#failIfNotLoggedIn()', ->
describe '#user()', ->
before ->
mock.connection.init()
@ -19,7 +21,7 @@ describe 'Auth Hooks:', ->
beforeEach (done) ->
mock.fs.init()
resin.data.prefix.set(resin.config.dataPrefix, done)
data.prefix.set(config.dataPrefix, done)
afterEach ->
mock.fs.restore()
@ -27,18 +29,18 @@ describe 'Auth Hooks:', ->
describe 'if not logged in', ->
beforeEach (done) ->
resin.auth.logout(done)
auth.logout(done)
it 'should not call the function', (done) ->
spy = sinon.spy()
authHooks.failIfNotLoggedIn(spy, _.noop)()
cliPermissions.user(spy, _.noop)()
_.defer ->
expect(spy).to.not.have.been.called
done()
it 'it should call the second function with an error', (done) ->
func = authHooks.failIfNotLoggedIn _.noop, (error) ->
func = cliPermissions.user _.noop, (error) ->
expect(error).to.be.an.instanceof(Error)
done()
func()
@ -48,7 +50,7 @@ describe 'Auth Hooks:', ->
# (auth.isLoggedIn). A try/catch works, but it still results
# in the error being printed in Mocha reporter.
xit 'should throw an error if no error handler function', ->
func = authHooks.failIfNotLoggedIn(_.noop)
func = cliPermissions.user(_.noop)
try
func()
catch error
@ -57,17 +59,17 @@ describe 'Auth Hooks:', ->
describe 'if logged in', ->
beforeEach (done) ->
nock(resin.config.remoteUrl)
nock(config.remoteUrl)
.post('/login_', johnDoeFixture.credentials)
.reply(200, johnDoeFixture.token)
resin.auth.login(johnDoeFixture.credentials, done)
auth.login(johnDoeFixture.credentials, done)
it 'should call the function with the correct arguments', (done) ->
args = [ 1, 2, 3, 'foo', 'bar' ]
spy = sinon.spy()
authHooks.failIfNotLoggedIn(spy, _.noop).apply(null, args)
cliPermissions.user(spy, _.noop).apply(null, args)
_.defer ->
expect(spy).to.have.been.calledWith(args...)
@ -75,7 +77,7 @@ describe 'Auth Hooks:', ->
it 'should not call the second function', (done) ->
spy = sinon.spy()
authHooks.failIfNotLoggedIn(_.noop, spy)()
cliPermissions.user(_.noop, spy)()
_.defer ->
expect(spy).to.not.have.been.called

View File

@ -3,6 +3,7 @@ program = require('commander')
pluralize = require('pluralize')
indefiniteArticle = require('indefinite-article')
log = require('../log/log')
cliPermissions = require('./cli-permissions')
exports.getArgument = (name) ->
return program[name]
@ -17,11 +18,23 @@ exports.setVersion = (version) ->
action: ->
log.out(version)
applyPermissions = (permission, action, onError) ->
permissionFunction = cliPermissions[permission]
if not _.isFunction(permissionFunction)
throw new Error("Invalid permission #{permission}")
return permissionFunction(action, onError)
exports.addCommand = (options = {}) ->
if options.permission?
action = applyPermissions(options.permission, options.action, options.onError)
else
action = options.action
program
.command(options.command)
.description(options.description)
.action(options.action)
.action(action)
return program
@ -40,24 +53,28 @@ exports.addResource = (options = {}) ->
command: "#{options.name}:create <name>"
description: "create #{nameArticle} #{options.displayName}"
action: options.actions.create
permission: options.permission
if _.isFunction(options.actions.list)
exports.addCommand
command: "#{pluralizedName}"
description: "list all #{pluralizedDisplayName}"
action: options.actions.list
permission: options.permission
if _.isFunction(options.actions.info)
exports.addCommand
command: "#{options.name} <id>"
description: "list a single #{options.displayName}"
action: options.actions.info
permission: options.permission
if _.isFunction(options.actions.remove)
exports.addCommand
command: "#{options.name}:rm <id>"
description: "remove #{nameArticle} #{options.displayName}"
action: options.actions.remove
permission: options.permission
exports.parse = (argv) ->
program.parse(argv)