Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
timoxley committed Aug 17, 2012
1 parent c2e9a77 commit 438a0d6
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 1 deletion.
17 changes: 16 additions & 1 deletion README.md
@@ -1,4 +1,19 @@
node-webhooks
=============

easily create webhooks
## Easily Create Webhooks

1. Create executable script called `webhook` in the directory you wish to
run it from.
2. Run `webhooks` command in same directory as `webhook` executable to
get the webhook key.
3. Boot webhooks with `webhooks start`
4. Hit webhook via your browser using your webhook key, e.g.
http://localhost:10010/CrfYl8CssJ7Jo0dYryVJYMV44CC5AcLi0At%2FF0DXa5TTiSQs%3D

### Security

Use this with much caution. I wouldn't use this on a production
machine. For increased security, set an environment var
WH_SECRET=mysecret when running `webhook` or `webhook start` to encrypt
using a custom keyphrase.
11 changes: 11 additions & 0 deletions bin/webhooks
@@ -0,0 +1,11 @@
#!/usr/bin/env node
'use strict'

var app = require('../')

if (process.argv[2] === 'start') {
var port = process.argv[3] || 10010
app.listen(port)
} else {
console.info(app.hashCwd())
}
3 changes: 3 additions & 0 deletions examples/simple/webhook
@@ -0,0 +1,3 @@
#!/bin/sh
touch it_worked
date >> it_worked
75 changes: 75 additions & 0 deletions index.js
@@ -0,0 +1,75 @@
'use strict'

var express = require('express')
var app = express()
app.use(express.errorHandler())
app.use(express.logger())
var crypto = require('crypto')
var assert = require('assert')
var domain = require('domain')
var fs = require('fs')
var child_process = require('child_process')

app.get('/:hash', function(req, res, next) {
if (!req.params.hash) {
console.warn('missing hash', req.params.hash)
return res.send(404)
}
var decryptionKey = process.env.WH_SECRET || 'keyboard cat'
try {
var dir = decrypt(req.params.hash, decryptionKey)
} catch (err) {
if (err+''.match(/DecipherFinal/)) {
console.warn('could not decipher', req.params.hash)
return res.send(404)
} else {
return next(err)
}
}
fs.exists(dir, function(exists) {
if (!exists) {
console.warn('directory does not exist!', dir)
return res.send(404)
}
console.info(dir)
child_process.exec(module.exports.command, {
cwd: dir
}, function(err) {
if (err) return next(err)
res.send(200)
})
})
})

var getId = function() {
os.hostname() + process.cwd()
}

module.exports = app

var ALGORITHM = 'cast5-cbc'
var FORMAT = 'base64'

var encrypt = module.exports.encrypt = function(id, password) {
assert.ok(id)
assert.ok(password)
var projectCipher = crypto.createCipher(ALGORITHM, password)
var final = projectCipher.update(id, 'utf8', FORMAT)
final += projectCipher.final(FORMAT)
return final
}

var decrypt = module.exports.decrypt = function(encrypted, password) {
assert.ok(encrypted)
assert.ok(password)
var projectDecipher = crypto.createDecipher(ALGORITHM, password)
var final = projectDecipher.update(encrypted, FORMAT, 'utf8')
final += projectDecipher.final('utf8')
return final
}

module.exports.hashCwd = function(cwd) {
return encodeURIComponent(encrypt(cwd || process.cwd(), process.env.WH_SECRET || 'keyboard cat'))
}

module.exports.command = './webhook'
28 changes: 28 additions & 0 deletions package.json
@@ -0,0 +1,28 @@
{
"name": "webhooks",
"version": "0.0.0",
"main": "index.js",
"bin": {
"webhook": "./bin/webhook"
},
"scripts": {
"test": "./node_modules/.bin/mocha test/*_test.js"
},
"license": "BSD",
"dependencies": {
"express": "~3.0.0rc3"
},
"devDependencies": {
"supertest": "~0.1.2",
"mocha": "~1.3.2"
},
"description": "Easily create webhooks",
"directories": {
"test": "test"
},
"repository": {
"type": "git",
"url": "git://github.com/timoxley/node-webhooks.git"
},
"author": "Tim Oxley"
}
47 changes: 47 additions & 0 deletions test/api_test.js
@@ -0,0 +1,47 @@
var request = require('supertest')
var app = require('../')
app.command = 'touch testing.js'

var assert = require('assert')
var fs = require('fs')

afterEach(function(done) {
fs.unlink('/tmp/testing.js', function() {
fs.unlink('./testing.js', function() {
done()
})
})
})

it('decodes hashes to paths', function(done) {
var hash = app.hashCwd()
request(app)
.get('/' + hash)
.expect(200, done)
})

it('decodes other hashes to paths', function(done) {
var hash = app.hashCwd('/tmp')
request(app)
.get('/' + hash)
.expect(200, done)
})

it('404 for invalid hashes', function(done) {
request(app)
.get('/garbage')
.expect(404, done)
})

it('runs commands at cwd', function(done) {
var hash = app.hashCwd('/tmp')
request(app)
.get('/' + hash)
.expect(200, function(err) {
assert.ifError(err)
fs.exists('/tmp/testing.js', function(exists) {
assert.ok(exists)
done()
})
})
})
40 changes: 40 additions & 0 deletions test/hashing_test.js
@@ -0,0 +1,40 @@
'use strict'

var encrypt = require('../').encrypt
var decrypt = require('../').decrypt
var hashCwd = require('../').hashCwd
var assert = require('assert')

it('can decrypt an encrypted message', function() {
var token = '/usr/bin'
var password = 'password'
var encrypted = encrypt(token, password)
assert.ok(encrypted != token)
assert.strictEqual(token, decrypt(encrypted, password))
})

it('can decrypt a "complex" encrypted message', function() {
var token = process.cwd()
token = 'Users/secoif/sdf'
var password = 'password'
var encrypted = encrypt(token, password)
assert.ok(encrypted != token)
assert.strictEqual(token, decrypt(encrypted, password))
})

it('doesn\'t decrypt garbage messages', function() {
var token = '/usr/bin'
var password = 'password'
var encrypted = encrypt(token, password)
assert.throws(function() {
decrypt('garbage', password)
})
})

it('getCwdHash encodes cwd()', function() {
assert.equal(process.cwd(), decrypt(decodeURIComponent(hashCwd()), 'keyboard cat'))
})

it('getCwdHash encodes passed in cwd()', function() {
assert.equal('/tmp', decrypt(decodeURIComponent(hashCwd('/tmp')), 'keyboard cat'))
})

0 comments on commit 438a0d6

Please sign in to comment.