hubot-auth
Version:
Assign roles to users and restrict command access in other scripts
163 lines (137 loc) • 5.9 kB
text/coffeescript
# Description
# Assign roles to users and restrict command access in other scripts.
#
# Configuration:
# HUBOT_AUTH_ADMIN - A comma separate list of user IDs
#
# Commands:
# hubot <user> has <role> role - Assigns a role to a user
# hubot <user> doesn't have <role> role - Removes a role from a user
# hubot what roles does <user> have - Find out what roles a user has
# hubot what roles do I have - Find out what roles you have
# hubot who has <role> role - Find out who has the given role
# hubot list assigned roles - List all assigned roles
# hubot what is my name - Tells you your name from persistent storage
# hubot what is my id - tells you your id from persistent storage
#
# Notes:
# * Call the method: robot.auth.hasRole(msg.envelope.user,'<role>')
# * returns bool true or false
#
# * the 'admin' role can only be assigned through the environment variable
# * roles are all transformed to lower case
#
# * The script assumes that user IDs will be unique on the service end as to
# correctly identify a user. Names were insecure as a user could impersonate
# a user
config =
admin_list: process.env.HUBOT_AUTH_ADMIN
module.exports = (robot) ->
unless config.admin_list?
robot.logger.warning 'The HUBOT_AUTH_ADMIN environment variable not set'
if config.admin_list?
admins = config.admin_list.split ','
else
admins = []
class Auth
isAdmin: (user) ->
user.id.toString() in admins
hasRole: (user, roles) ->
userRoles = @userRoles(user)
if userRoles?
roles = [roles] if typeof roles is 'string'
for role in roles
return true if role in userRoles
return false
usersWithRole: (role) ->
users = []
for own key, user of robot.brain.data.users
if @hasRole(user, role)
users.push(user.name)
users
userRoles: (user) ->
roles = []
if user? and robot.auth.isAdmin user
roles.push('admin')
if user.roles?
roles = roles.concat user.roles
roles
robot.auth = new Auth
robot.respond /@?(.+) ha(?:s|ve) (["'\w: -_]+) role/i, (msg) ->
name = msg.match[1].trim()
if name.toLowerCase() is 'i' then name = msg.message.user.name
if name.match(/(.*)(?:don['’]t|doesn['’]t|do not|does not)/i) then return
unless name.toLowerCase() in ['', 'who', 'what', 'where', 'when', 'why']
unless robot.auth.isAdmin msg.message.user
msg.reply "Sorry, only admins can assign roles."
else
newRole = msg.match[2].trim().toLowerCase()
user = robot.brain.userForName(name)
return msg.reply "#{name} does not exist" unless user?
user.roles or= []
if newRole in user.roles
msg.reply "#{name} already has the '#{newRole}' role."
else
if newRole is 'admin'
msg.reply "Sorry, the 'admin' role can only be defined in the HUBOT_AUTH_ADMIN env variable."
else
myRoles = msg.message.user.roles or []
user.roles.push(newRole)
msg.reply "OK, #{name} has the '#{newRole}' role."
robot.respond /@?(.+) (?:don['’]t|doesn['’]t|do not|does not) have (["'\w: -_]+) role/i, (msg) ->
name = msg.match[1].trim()
if name.toLowerCase() is 'i' then name = msg.message.user.name
unless name.toLowerCase() in ['', 'who', 'what', 'where', 'when', 'why']
unless robot.auth.isAdmin msg.message.user
msg.reply "Sorry, only admins can remove roles."
else
newRole = msg.match[2].trim().toLowerCase()
user = robot.brain.userForName(name)
return msg.reply "#{name} does not exist" unless user?
user.roles or= []
if newRole is 'admin'
msg.reply "Sorry, the 'admin' role can only be removed from the HUBOT_AUTH_ADMIN env variable."
else
myRoles = msg.message.user.roles or []
user.roles = (role for role in user.roles when role isnt newRole)
msg.reply "OK, #{name} doesn't have the '#{newRole}' role."
robot.respond /what roles? do(es)? @?(.+) have\?*$/i, (msg) ->
name = msg.match[2].trim()
if name.toLowerCase() is 'i' then name = msg.message.user.name
user = robot.brain.userForName(name)
return msg.reply "#{name} does not exist" unless user?
userRoles = robot.auth.userRoles(user)
if userRoles.length == 0
msg.reply "#{name} has no roles."
else
msg.reply "#{name} has the following roles: #{userRoles.join(', ')}."
robot.respond /who has (["'\w: -_]+) role\?*$/i, (msg) ->
role = msg.match[1]
userNames = robot.auth.usersWithRole(role) if role?
if userNames.length > 0
msg.reply "The following people have the '#{role}' role: #{userNames.join(', ')}"
else
msg.reply "There are no people that have the '#{role}' role."
robot.respond /list assigned roles/i, (msg) ->
roles = []
unless robot.auth.isAdmin msg.message.user
msg.reply "Sorry, only admins can list assigned roles."
else
for i, user of robot.brain.data.users when user.roles
roles.push role for role in user.roles when role not in roles
if roles.length > 0
msg.reply "The following roles are available: #{roles.join(', ')}"
else
msg.reply "No roles to list."
robot.respond /what(?:'s|s|\s+is)\s+my\s+name\s*(?:\?|)/i, (msg) ->
user = robot.brain.userForId(msg.envelope.user['id'])
unless user and user['name']
msg.reply "Your user could not be found in my Brain, sorry!"
return
msg.reply "Your name is: #{user['name']}."
robot.respond /what(?:'s|s|\s+is)\s+my\s+id\s*(?:\?|)/i, (msg) ->
user = robot.brain.userForId(msg.envelope.user['id'])
unless user and user['id']
msg.reply "Your user could not be found in my Brain, sorry!"
return
msg.reply "Your ID is: #{user['id']}."