Skip to content

Commit 9bb42aa

Browse files
committed
Initial commit.
0 parents  commit 9bb42aa

10 files changed

+299
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

.travis.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
language: node_js
2+
node_js:
3+
- "0.11"
4+
- "0.10"
5+
notifications:
6+
email: false

Gruntfile.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
module.exports = function(grunt) {
4+
5+
grunt.loadNpmTasks('grunt-mocha-test');
6+
grunt.loadNpmTasks('grunt-release');
7+
8+
grunt.initConfig({
9+
mochaTest: {
10+
test: {
11+
options: {
12+
reporter: 'spec',
13+
require: 'coffee-script'
14+
},
15+
src: ['test/**/*.coffee']
16+
}
17+
},
18+
release: {
19+
options: {
20+
tagName: 'v<%= version %>',
21+
commitMessage: 'Prepared to release <%= version %>.'
22+
}
23+
},
24+
watch: {
25+
files: ['Gruntfile.js', 'test/**/*.coffee'],
26+
tasks: ['test']
27+
}
28+
});
29+
30+
grunt.event.on('watch', function(action, filepath, target) {
31+
grunt.log.writeln(target + ': ' + filepath + ' has ' + action);
32+
});
33+
34+
// load all grunt tasks
35+
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
36+
37+
grunt.registerTask('test', ['mochaTest']);
38+
grunt.registerTask('test:watch', ['watch']);
39+
grunt.registerTask('default', ['test']);
40+
};

README.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Hubot: hubot-auth
2+
3+
Assign roles to users and restrict command access in other scripts.
4+
5+
See [`src/auth.coffee`](src/auth.coffee) for full documentation.
6+
7+
## Installation
8+
9+
Add **hubot-auth** to your `package.json` file:
10+
11+
```json
12+
"dependencies": {
13+
"hubot": ">= 2.5.1",
14+
"hubot-scripts": ">= 2.4.2",
15+
"hubot-auth": ">= 0.0.0",
16+
"hubot-hipchat": "~2.5.1-5",
17+
}
18+
```
19+
20+
Add **hubot-auth** to your `external-scripts.json`:
21+
22+
```json
23+
["hubot-auth"]
24+
```
25+
26+
Run `npm install`
27+
28+
## Sample Interaction
29+
30+
```
31+
user1>> hubot hello
32+
hubot>> hello!
33+
```

index.coffee

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fs = require 'fs'
2+
path = require 'path'
3+
4+
module.exports = (robot, scripts) ->
5+
scriptsPath = path.resolve(__dirname, 'src')
6+
fs.exists scriptsPath, (exists) ->
7+
if exists
8+
for script in fs.readdirSync(scriptsPath)
9+
if scripts? and '*' not in scripts
10+
robot.loadFile(scriptsPath, script) if script in scripts
11+
else
12+
robot.loadFile(scriptsPath, script)

package.json

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "hubot-auth",
3+
"description": "Assign roles to users and restrict command access in other scripts",
4+
"version": "0.0.0",
5+
"author": "Alex Williams (http://github.com/aw)",
6+
"contributors": [
7+
"technicalpickles",
8+
"tombell",
9+
"robertfwest",
10+
"superkarn",
11+
"omares",
12+
"rafaelfranca",
13+
"mizzy",
14+
"jhubert",
15+
"davereid",
16+
"patcon"
17+
],
18+
"license": "MIT",
19+
20+
"keywords": ["hubot","hubot-scripts","authentication","roles"],
21+
22+
"repository": {
23+
"type": "git",
24+
"url": "git://github.com/hubot-scripts/hubot-auth.git"
25+
},
26+
27+
"bugs": {
28+
"url": "https://github.com/hubot-scripts/hubot-auth/issues"
29+
},
30+
31+
"dependencies": {
32+
"coffee-script": "~1.6"
33+
},
34+
35+
"devDependencies": {
36+
"mocha": "*",
37+
"chai": "*",
38+
"sinon-chai": "*",
39+
"sinon": "*",
40+
"grunt-mocha-test": "~0.7.0",
41+
"grunt-release": "~0.6.0",
42+
"matchdep": "~0.1.2",
43+
"grunt-contrib-watch": "~0.5.3"
44+
},
45+
46+
"main": "index.coffee",
47+
48+
"scripts": {
49+
"test": "grunt test"
50+
}
51+
}

script/bootstrap

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
3+
# Make sure everything is development forever
4+
export NODE_ENV=development
5+
6+
# Load environment specific environment variables
7+
if [ -f .env ]; then
8+
source .env
9+
fi
10+
11+
if [ -f .env.${NODE_ENV} ]; then
12+
source .env.${NODE_ENV}
13+
fi
14+
15+
npm install
16+
17+
# Make sure coffee and mocha are on the path
18+
export PATH="node_modules/.bin:$PATH"

script/test

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
3+
# bootstrap environment
4+
source script/bootstrap
5+
6+
mocha --compilers coffee:coffee-script

src/auth.coffee

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Description
2+
# Assign roles to users and restrict command access in other scripts.
3+
#
4+
# Configuration:
5+
# HUBOT_AUTH_ADMIN - A comma separate list of user IDs
6+
#
7+
# Commands:
8+
# hubot <user> has <role> role - Assigns a role to a user
9+
# hubot <user> doesn't have <role> role - Removes a role from a user
10+
# hubot what role does <user> have - Find out what roles are assigned to a specific user
11+
# hubot who has admin role - Find out who's an admin and can assign roles
12+
#
13+
# Notes:
14+
# * Call the method: robot.auth.hasRole(msg.envelope.user,'<role>')
15+
# * returns bool true or false
16+
#
17+
# * the 'admin' role can only be assigned through the environment variable
18+
# * roles are all transformed to lower case
19+
#
20+
# * The script assumes that user IDs will be unique on the service end as to
21+
# correctly identify a user. Names were insecure as a user could impersonate
22+
# a user
23+
24+
module.exports = (robot) ->
25+
26+
unless process.env.HUBOT_AUTH_ADMIN?
27+
robot.logger.warning 'The HUBOT_AUTH_ADMIN environment variable not set'
28+
29+
if process.env.HUBOT_AUTH_ADMIN?
30+
admins = process.env.HUBOT_AUTH_ADMIN.split ','
31+
else
32+
admins = []
33+
34+
class Auth
35+
hasRole: (user, roles) ->
36+
user = robot.brain.userForId(user.id)
37+
if user? and user.roles?
38+
roles = [roles] if typeof roles is 'string'
39+
for role in roles
40+
return true if role in user.roles
41+
return false
42+
43+
usersWithRole: (role) ->
44+
users = []
45+
for own key, user of robot.brain.data.users
46+
if robot.auth.hasRole(msg.envelope.user, role)
47+
users.push(user)
48+
users
49+
50+
robot.auth = new Auth
51+
52+
robot.respond /@?(.+) (has) (["'\w: -_]+) (role)/i, (msg) ->
53+
name = msg.match[1].trim()
54+
newRole = msg.match[3].trim().toLowerCase()
55+
56+
unless name.toLowerCase() in ['', 'who', 'what', 'where', 'when', 'why']
57+
user = robot.brain.userForName(name)
58+
return msg.reply "#{name} does not exist" unless user?
59+
user.roles or= []
60+
61+
if newRole in user.roles
62+
msg.reply "#{name} already has the '#{newRole}' role."
63+
else
64+
if newRole is 'admin'
65+
msg.reply "Sorry, the 'admin' role can only be defined in the HUBOT_AUTH_ADMIN env variable."
66+
else
67+
myRoles = msg.message.user.roles or []
68+
if msg.message.user.id.toString() in admins
69+
user.roles.push(newRole)
70+
msg.reply "Ok, #{name} has the '#{newRole}' role."
71+
72+
robot.respond /@?(.+) (doesn't have|does not have) (["'\w: -_]+) (role)/i, (msg) ->
73+
name = msg.match[1].trim()
74+
newRole = msg.match[3].trim().toLowerCase()
75+
76+
unless name.toLowerCase() in ['', 'who', 'what', 'where', 'when', 'why']
77+
user = robot.brain.userForName(name)
78+
return msg.reply "#{name} does not exist" unless user?
79+
user.roles or= []
80+
81+
if newRole is 'admin'
82+
msg.reply "Sorry, the 'admin' role can only be removed from the HUBOT_AUTH_ADMIN env variable."
83+
else
84+
myRoles = msg.message.user.roles or []
85+
if msg.message.user.id.toString() in admins
86+
user.roles = (role for role in user.roles when role isnt newRole)
87+
msg.reply "Ok, #{name} doesn't have the '#{newRole}' role."
88+
89+
robot.respond /(what role does|what roles does) @?(.+) (have)\?*$/i, (msg) ->
90+
name = msg.match[2].trim()
91+
user = robot.brain.userForName(name)
92+
return msg.reply "#{name} does not exist" unless user?
93+
user.roles or= []
94+
displayRoles = user.roles
95+
96+
if user.id.toString() in admins
97+
displayRoles.push('admin')
98+
99+
if displayRoles.length == 0
100+
msg.reply "#{name} has no roles."
101+
else
102+
msg.reply "#{name} has the following roles: #{displayRoles.join(', ')}."
103+
104+
robot.respond /who has admin role\?*$/i, (msg) ->
105+
adminNames = []
106+
for admin in admins
107+
user = robot.brain.userForId(admin)
108+
adminNames.push user.name if user?
109+
110+
if adminNames.length > 0
111+
msg.reply "The following people have the 'admin' role: #{adminNames.join(', ')}"
112+
else
113+
msg.reply "There are no people that have the 'admin' role."

test/auth-test.coffee

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
chai = require 'chai'
2+
sinon = require 'sinon'
3+
chai.use require 'sinon-chai'
4+
5+
expect = chai.expect
6+
7+
describe 'hello-world', ->
8+
beforeEach ->
9+
@robot =
10+
respond: sinon.spy()
11+
hear: sinon.spy()
12+
13+
require('../src/hello-world')(@robot)
14+
15+
it 'registers a respond listener', ->
16+
expect(@robot.respond).to.have.been.calledWith(/hello/)
17+
18+
it 'registers a hear listener', ->
19+
expect(@robot.hear).to.have.been.calledWith(/orly/)

0 commit comments

Comments
 (0)