This commit is contained in:
Jeff Cross
2012-12-19 09:48:31 -07:00
10 changed files with 95 additions and 41 deletions

View File

@@ -3,23 +3,25 @@
## 0.7.0
### New Features
- New utilities for extending Resource Types.
- Added `Resource.extend("ResourceName", { /* members */ })` syntax for extending Resources. The `init()` function is used as a constructor. The old `util.inherits()` syntax will continue to work.
- Moved `Resource` base class to the exports of the deployd module. You can now use `require('deployd').Resource` instead of `require('deployd/lib/resource')`.
- Added `get(ctx, next)`, `post(ctx, next)`, `put(ctx, next)`, and `del(ctx, next)` utility functions on `Resource`. You can now override those instead of `handle()`.
- New `Module` type in extension API
- Modules can define multiple Resource Types with `this.addResourceType()`
- [TODO] Modules can register their own dashboards.
- Added `dir` to server options - for booting in other directories than `process.cwd()`.
- Resources now support custom events by default
- New collection permission api
- New utilities for extending Resource Types.
- Added `Resource.extend("ResourceName", { /* members */ })` syntax for extending Resources. The `init()` function is used as a constructor. The old `util.inherits()` syntax will continue to work.
- Moved `Resource` base class to the exports of the deployd module. You can now use `require('deployd').Resource` instead of `require('deployd/lib/resource')`.
- Added `get(ctx, next)`, `post(ctx, next)`, `put(ctx, next)`, and `del(ctx, next)` utility functions on `Resource`. You can now override those instead of `handle()`.
- New `Module` type in extension API
- Modules can define multiple Resource Types with `this.addResourceType()`
- [TODO] Modules can register their own dashboards.
- Added `dir` to server options - for booting in other directories than `process.cwd()`.
- Added `errorTemplate` to server options - for overriding the default error template.
- Resources now support custom events by default
- New collection permission api
### Breaking Changes
- Most configuration properties on the `Resource` class have been moved to the prototype: `external`, `events`, `basicDashboard`, and `dashboard`.
- The `label` and `defaultType` properties will remain on the constructor, as they shouldn't be inherited.
- The configuration option `Resource.events` has been renamed `Resource.eventNames`.
- Most configuration properties on the `Resource` class have been moved to the prototype: `external`, `events`, `basicDashboard`, and `dashboard`.
- The `label` and `defaultType` properties will remain on the constructor, as they shouldn't be inherited.
- The configuration option `Resource.events` has been renamed `Resource.eventNames`.
- Anonymous sessions are now destroyed every time the server starts.
### Major Bugfixes

View File

@@ -103,19 +103,34 @@ Cluster.prototype.emitToUsers = function (uids, ev, data) {
}
Cluster.prototype.emitToServer = function(host, ev, data, sids) {
var body = {
event: ev,
data: data
};
var cluster = this;
if(sids) {
body.sids = sids;
if(cluster.rootKey) {
emit();
} else {
process.server.keys.getLocal(function (err, key) {
if(err) throw err;
cluster.rootKey = key;
emit();
});
}
try {
request.post({url: 'http://' + host + '/__proxy', json: body});
} catch(e) {
delete this.remotes[host];
function emit() {
var headers = {'dpd-ssh-key': cluster.rootKey};
var body = {
event: ev,
data: data
};
if(sids) {
body.sids = sids;
}
try {
request.post({url: 'http://' + host + '/__proxy', headers: headers, json: body});
} catch(e) {
delete cluster.remotes[host];
}
}
}

View File

@@ -1,6 +1,7 @@
var internalClient = require('./internal-client')
, debug = require('debug')('context')
, respond = require('doh').createResponder();
, doh = require('doh')
, respond;
/**
* A `Context` gives access to a `req` and `res` object when passed to `resource.handle()`,
@@ -21,6 +22,11 @@ var internalClient = require('./internal-client')
function Context(resource, req, res, server) {
var ctx = this;
if(!respond) {
respond = doh.createResponder({template: server.options.errorTemplate})
}
this.url = req.url.slice(resource.path.length).split('?')[0];
if (this.url.indexOf('/') !== 0) this.url = '/' + this.url;

View File

@@ -119,25 +119,26 @@ function getConnection(db, fn) {
} else {
db.connecting = true;
db._mdb.open(function (err) {
db.connecting = false;
db.emit('connection attempted', err);
if(err) {
db.connected = false;
throw err;
} else {
// check for credentials
var credentials = db.options.credentials;
if (credentials && credentials.username && credentials.password) {
db._mdb.authenticate(credentials.username, credentials.password, function (err) {
db.connecting = false;
if (err) {
db.connected = false;
throw err;
}
db.connected = true;
db.emit('connection attempted', err);
fn(null, db._mdb);
});
} else {
db.connecting = false;
db.emit('connection attempted', err);
db.connected = true;
fn(null, db._mdb);
}

View File

@@ -63,7 +63,7 @@ InternalResources.prototype.handle = function(ctx, next) {
var c = types[key]
, pages = c.prototype.dashboard && c.prototype.dashboard.pages;
if (!pages && c.eventNames) {
if (!pages && c.prototype.eventNames) {
pages = ['Config', 'Events'];
}
result[key] = {

View File

@@ -181,6 +181,30 @@ UserCollection.prototype.hash = function (password, salt) {
return crypto.createHmac('sha256', salt).update(password).digest('hex');
};
UserCollection.prototype.getRequiredPermissions = function (ctx) {
var requiredPermissions = Collection.prototype.getRequiredPermissions.apply(this, arguments);
if(ctx.method === 'post' && ctx.url === '/login') {
requiredPermissions['login'] = true;
}
if(ctx.method === 'post' && ctx.url === '/logout') {
requiredPermissions['logout'] = true;
}
return requiredPermissions;
}
UserCollection.prototype.getDefaultPermissions = function (ctx) {
var defaultPermissions = Collection.prototype.getDefaultPermissions.apply(this, arguments);
defaultPermissions['login'] = true;
defaultPermissions['logout'] = true;
return defaultPermissions;
}
UserCollection.label = 'Users Collection';
UserCollection.defaultPath = '/users';

View File

@@ -3,7 +3,7 @@ var db = require('./db')
, escapeRegExp = /[\-\[\]{}()+?.,\\\^$|#\s]/g
, debug = require('debug')('router')
, doh = require('doh')
, error404 = doh.createResponder()
, error404
, async = require('async');
/**
@@ -15,6 +15,10 @@ var db = require('./db')
*/
function Router(resources, server) {
if(!error404) {
error404 = doh.createResponder({template: server.options.errorTemplate});
}
this.resources = resources || [];
this.server = server;
}

View File

@@ -10,6 +10,7 @@ var http = require('http')
, setupReqRes = require('./util/http').setup
, debug = require('debug')('server')
, config = require('./config-loader')
, path = require('path')
, Cluster = require('./cluster');
function extend(origin, add) {
@@ -80,7 +81,7 @@ function Server(options) {
var sessionStore = this.sessions = new SessionStore('sessions', this.db, this.sockets, cluster);
// persist keys in a store
var keys = this.keys = new Keys();
var keys = this.keys = new Keys(path.join(options.dir, '.dpd/keys.json'));
this.on('request', function (req, res) {
// dont handle socket.io requests
@@ -92,7 +93,7 @@ function Server(options) {
setupReqRes(req, res, function(err, next) {
if(err) return res.end(err.message);
sessionStore.createSession(req.cookies.get('sid'), function(err, session) {
sessionStore.createSession(req.headers['dpd-auth-token'] || req.cookies.get('sid'), function(err, session) {
if(err) {
debug('session error', err, session);
@@ -103,6 +104,12 @@ function Server(options) {
req.session = session;
var route = function() {
// XXX - need to require root
if(req.url === '/__proxy' && req.isRoot) {
cluster.handleProxy(req, res);
return;
}
config.loadConfig(options.dir, server, function(err, results) {
if (err) throw err;
server.resources = results.resources;
@@ -118,14 +125,6 @@ function Server(options) {
var root = req.headers['dpd-ssh-key'] || req.cookies.get('DpdSshKey');
// XXX - need to require root
if(req.url === '/__proxy') {
cluster.handleProxy(req, res);
return;
}
if (options.env === 'development') {
if (root) { req.isRoot = true; }
route();

View File

@@ -41,6 +41,9 @@ function SessionStore(namespace, db, sockets) {
}
Store.apply(this, arguments);
// clear annonymous sessions
this.remove({uid: {$exists: false}});
}
util.inherits(SessionStore, Store);
exports.SessionStore = SessionStore;

View File

@@ -12,7 +12,7 @@ var Server = require('./server')
commands.start = function (config, fn) {
var server = new Server(config);
// TODO: Re-enable
// upgrade(server);
// upgrade(server, {template: server.options.errorTemplate});
server.on('listening', fn);
server.on('error', fn);
server.listen();