Skip to content

Commit

Permalink
Merge pull request #13 from webcast-io/feature/basic-auth
Browse files Browse the repository at this point in the history
Basic Authentication
  • Loading branch information
paulbjensen committed Apr 26, 2014
2 parents 3cd847a + 8660f42 commit a7809b9
Show file tree
Hide file tree
Showing 9 changed files with 245 additions and 123 deletions.
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Features
---

- Create, modify, and remove jobs via a REST API
- Basic authentication
- Store arbitrary data in the job
- Transmit data on job updates via Web Hooks
- Quick start using jobukyu's command line interface
Expand Down Expand Up @@ -54,6 +55,16 @@ Usage

The Job Queue is accessed via a REST API. There is a single resource called <code>job</code>.

Adding Authentication
---

In your config file add the hash `auth` with elements username and password.

auth: {
username: 'CrazyEd',
password: 'd03sJ0bukyu'
}

REST API
---

Expand Down Expand Up @@ -86,10 +97,14 @@ Installing git release:

$ npm install -g git://github.com/webcast-io/jobukyu

Running using CLI
Run using CLI

$ jobukyu

Running useing CLI (with a path to a config file)
Run using CLI (with a path to a config file)

$ jobukyu --config ./my_custom_config.json

Run using CLI (with a default/example config)

$ jobukyu --default-config
30 changes: 25 additions & 5 deletions bin/jobukyu
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,37 @@
// Dependencies
//

var argv = require('optimist').argv;
var path = require('path');
var argv = require('optimist').argv;
var path = require('path');
var http = require('http');
var createApp = require('../index');

//
// Run
//

process.env.JOBUKYU_CONFIG_PATH = process.env.JOBUKYU_CONFIG_PATH || argv.config || './config';
var configPath, config;

if(argv['default-config']) {
process.env.JOBUKYU_CONFIG_PATH = path.resolve(__dirname + '/../config.example.js');
configPath = __dirname + '/../config.example.js';
} else {
configPath = argv.config || './config';
}

require('../index');
configPath = path.resolve(configPath || './config');

try {
config = require(configPath);
} catch (e) {
console.error('Unable to open config module/file ' + configPath);
process.exit(1);
}

var app = createApp(config);


// Start the server
//
http.createServer(app).listen(config.port, function(){
console.log('Jobukyu is listening on port', config.port);
});
156 changes: 47 additions & 109 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,124 +5,62 @@
// Dependencies
//

var http = require('http');
var path = require('path');
var connect = require('connect');
var connectRoute = require('connect-route');
var router = require('./lib/router');
var mongoose = require('mongoose');

var configPath = path.resolve(process.env.JOBUKYU_CONFIG_PATH || './config'), config;
try {
config = require(process.env.JOBUKYU_CONFIG_PATH || './config');
} catch (e) {
console.error('Unable to open config module/file ' + configPath);
process.exit(1);
}


// App
//
var app = connect();



// Use the logger if environment config allows
//
if (config.log) {
app.use(connect.logger('dev'));
}



// Append connect middleware
//
app.use(connect.query());
app.use(connect.json());



// Defines support for res.json in controller
// actions
//
// @req {Object} The http request object
// @res {Object} The http response object
// @next {Function} The function to execute once finished
//
app.use(function (req,res, next) {
res.json = function (statusCodeOrBody, body) {
var status = 200;
if (typeof statusCodeOrBody === 'number') {
status = statusCodeOrBody;
} else {
body = statusCodeOrBody;
}
res.setHeader('Content-Type', 'application/json');
res.statusCode = status;
res.end(JSON.stringify(body));
function createApp(config, mongo) {

// App
//
var app = connect();

// Use the logger if environment config allows
//
if (config.log) {
app.use(connect.logger('dev'));
}

// Append connect middleware
//
app.use(connect.query());
app.use(connect.json());

app.use(require('./lib/res.json.js'));

// Database connection
//
app.db = (mongo) ? mongo : mongoose.connect(config.mongo.url);

// Models
//
if(app.db.models.Job) {
app.models = {
job: app.db.models.Job
};
} else {
app.models = {
job: require('./lib/models/job')(app.db).model
};
}

// Controllers
//
app.controllers = {
jobs: require('./lib/controllers/jobs')(app),
site: require('./lib/controllers/site')(),
auth: require('./lib/controllers/auth')(config)
};
next();
});



// Database connection
//
app.db = mongoose.connect(config.mongo.url);



// Models
//
app.models = {
job: require('./lib/models/job')(app.db).model
};



// Controllers
//
app.controllers = {
jobs: require('./lib/controllers/jobs')(app),
site: require('./lib/controllers/site')()
};
app.use(app.controllers.auth.isAuth);
app.use(router(app));


return app;

////////////////
/* API routes */
////////////////

app.use(connectRoute(function (router) {

router.get('/', app.controllers.site.index);
router.get('/jobs', app.controllers.jobs.index);
router.post('/jobs', app.controllers.jobs.create);
router.get('/jobs/search', app.controllers.jobs.search);
router.get('/jobs/new', app.controllers.jobs.new);
router.get('/jobs/processing', app.controllers.jobs.processing);
router.get('/jobs/completed', app.controllers.jobs.completed);
router.get('/jobs/failed', app.controllers.jobs.failed);
router.get('/jobs/:id', app.controllers.jobs.show);
router.put('/jobs/:id', app.controllers.jobs.update);
router.put('/jobs/:id/take', app.controllers.jobs.take);
router.put('/jobs/:id/release', app.controllers.jobs.release);
router.put('/jobs/:id/complete', app.controllers.jobs.complete);
router.put('/jobs/:id/fail', app.controllers.jobs.fail);
router.put('/jobs/:id/retry', app.controllers.jobs.retry);
router.delete('/jobs/:id', app.controllers.jobs.delete);

}));



// Start the server
//
http.createServer(app).listen(config.port, function(){
console.log('Jobukyu is listening on port', config.port);
});

}


// Expose the app as the public API
//
module.exports = app;
module.exports = createApp;
38 changes: 38 additions & 0 deletions lib/controllers/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

var auth = require('basic-auth');


// Loads the controller
//
// @app {Object} The config
//
function main (config) {

return {

isAuth: function(req, res, next) {

if(!config.auth) {
return next();
}

var user = auth(req);

if(
config.auth &&
user &&
config.auth.username === user.name &&
config.auth.password === user.pass
) {
return next();
}

res.json(403, { message: 'Permission Denied' });
}

};

}

module.exports = main;
1 change: 0 additions & 1 deletion lib/controllers/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ function main () {
// GET /
//
index: function (req,res) {
console.log();
readFileFromCache(__dirname + '/../views/site/index.html', function(err, data){
if (err) {
res.json(500, err);
Expand Down
24 changes: 24 additions & 0 deletions lib/res.json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

// Defines support for res.json in controller
// actions
//
// @req {Object} The http request object
// @res {Object} The http response object
// @next {Functioroutern} The function to execute once finished
//
module.exports = function (req,res, next) {

res.json = function (statusCodeOrBody, body) {
var status = 200;
if (typeof statusCodeOrBody === 'number') {
status = statusCodeOrBody;
} else {
body = statusCodeOrBody;
}
res.setHeader('Content-Type', 'application/json');
res.statusCode = status;
res.end(JSON.stringify(body));
};
next();
};
33 changes: 33 additions & 0 deletions lib/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

'use strict';

var connectRoute = require('connect-route');

module.exports = function(app) {

////////////////
/* API routes */
////////////////

return connectRoute(function (router) {

router.get('/', app.controllers.site.index);
router.get('/jobs', app.controllers.jobs.index);
router.post('/jobs', app.controllers.jobs.create);
router.get('/jobs/search', app.controllers.jobs.search);
router.get('/jobs/new', app.controllers.jobs.new);
router.get('/jobs/processing', app.controllers.jobs.processing);
router.get('/jobs/completed', app.controllers.jobs.completed);
router.get('/jobs/failed', app.controllers.jobs.failed);
router.get('/jobs/:id', app.controllers.jobs.show);
router.put('/jobs/:id', app.controllers.jobs.update);
router.put('/jobs/:id/take', app.controllers.jobs.take);
router.put('/jobs/:id/release', app.controllers.jobs.release);
router.put('/jobs/:id/complete', app.controllers.jobs.complete);
router.put('/jobs/:id/fail', app.controllers.jobs.fail);
router.put('/jobs/:id/retry', app.controllers.jobs.retry);
router.delete('/jobs/:id', app.controllers.jobs.delete);

});

};
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "A Job Queue REST API",
"main": "index.js",
"scripts": {
"start": "node index.js",
"start": "./bin/jobukyu",
"config": "cp config.example.js config.js",
"test": "NODE_ENV=test node_modules/.bin/mocha",
"coverage": "NODE_ENV=test ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha --report lcov -- -R spec test/*.js",
Expand Down Expand Up @@ -39,7 +39,8 @@
"lodash": "~2.0.0",
"mongoose": "~3.6.19",
"request": "~2.27.0",
"optimist": "~0.6.0"
"optimist": "~0.6.0",
"basic-auth": "0.0.1"
},
"bin": "bin/jobukyu"
}
Loading

0 comments on commit a7809b9

Please sign in to comment.