Merge branch 'release/1.6.2' into production

This commit is contained in:
Raymond Feng 2014-02-12 11:35:41 -08:00
commit ec3535e550
9 changed files with 113 additions and 56 deletions

View File

@ -305,7 +305,9 @@ app.enableAuth = function() {
next(); next();
} }
}); });
}
this.isAuthEnabled = true;
};
/** /**
* Initialize an application from an options object or a set of JSON and JavaScript files. * Initialize an application from an options object or a set of JSON and JavaScript files.
@ -319,7 +321,7 @@ app.enableAuth = function() {
* *
* **Options** * **Options**
* *
* - `cwd` - _optional_ - the directory to use when loading JSON and JavaScript files * - `appRootDir` - _optional_ - the directory to use when loading JSON and JavaScript files
* - `models` - _optional_ - an object containing `Model` definitions * - `models` - _optional_ - an object containing `Model` definitions
* - `dataSources` - _optional_ - an object containing `DataSource` definitions * - `dataSources` - _optional_ - an object containing `DataSource` definitions
* *

View File

@ -57,6 +57,11 @@ function createApplication() {
utils.merge(app, proto); utils.merge(app, proto);
// Create a new instance of models registry per each app instance
app.models = function() {
return proto.models.apply(this, arguments);
};
return app; return app;
} }

View File

@ -98,12 +98,13 @@ var crypto = require('crypto');
function generateKey(hmacKey, algorithm, encoding) { function generateKey(hmacKey, algorithm, encoding) {
hmacKey = hmacKey || 'loopback'; hmacKey = hmacKey || 'loopback';
algorithm = algorithm || 'sha256'; algorithm = algorithm || 'sha1';
encoding = encoding || 'base64'; encoding = encoding || 'hex';
var hmac = crypto.createHmac(algorithm, hmacKey); var hmac = crypto.createHmac(algorithm, hmacKey);
var buf = crypto.randomBytes(64); var buf = crypto.randomBytes(32);
hmac.update(buf); hmac.update(buf);
return hmac.digest('base64'); var key = hmac.digest(encoding);
return key;
} }
/** /**
@ -121,7 +122,7 @@ var Application = loopback.createModel('Application', ApplicationSchema);
Application.beforeCreate = function (next) { Application.beforeCreate = function (next) {
var app = this; var app = this;
app.created = app.modified = new Date(); app.created = app.modified = new Date();
app.id = generateKey('id', 'sha1'); app.id = generateKey('id', 'md5');
app.clientKey = generateKey('client'); app.clientKey = generateKey('client');
app.javaScriptKey = generateKey('javaScript'); app.javaScriptKey = generateKey('javaScript');
app.restApiKey = generateKey('restApi'); app.restApiKey = generateKey('restApi');
@ -208,13 +209,18 @@ Application.authenticate = function (appId, key, cb) {
cb && cb(err, null); cb && cb(err, null);
return; return;
} }
var matched = null; var result = null;
['clientKey', 'javaScriptKey', 'restApiKey', 'windowsKey', 'masterKey'].forEach(function (k) { var keyNames = ['clientKey', 'javaScriptKey', 'restApiKey', 'windowsKey', 'masterKey'];
if (app[k] === key) { for (var i = 0; i < keyNames.length; i++) {
matched = k; if (app[keyNames[i]] === key) {
result = {
application: app,
keyType: keyNames[i]
};
break;
} }
}); }
cb && cb(null, matched); cb && cb(null, result);
}); });
}; };

View File

@ -117,10 +117,20 @@ Model.setup = function () {
/*! /*!
* Get the reference to ACL in a lazy fashion to avoid race condition in require * Get the reference to ACL in a lazy fashion to avoid race condition in require
*/ */
var ACL = null; var _aclModel = null;
function getACL() { Model._ACL = function getACL(ACL) {
return ACL || (ACL = require('./acl').ACL); if(ACL !== undefined) {
} // The function is used as a setter
_aclModel = ACL;
}
if(_aclModel) {
return _aclModel;
}
var aclModel = require('./acl').ACL;
_aclModel = loopback.getModelByType(aclModel);
return _aclModel;
};
/** /**
* Check if the given access token can invoke the method * Check if the given access token can invoke the method
@ -137,9 +147,9 @@ function getACL() {
Model.checkAccess = function(token, modelId, method, callback) { Model.checkAccess = function(token, modelId, method, callback) {
var ANONYMOUS = require('./access-token').ANONYMOUS; var ANONYMOUS = require('./access-token').ANONYMOUS;
token = token || ANONYMOUS; token = token || ANONYMOUS;
var ACL = getACL(); var aclModel = Model._ACL();
var methodName = 'string' === typeof method? method: method && method.name; var methodName = 'string' === typeof method? method: method && method.name;
ACL.checkAccessForToken(token, this.modelName, modelId, methodName, callback); aclModel.checkAccessForToken(token, this.modelName, modelId, methodName, callback);
}; };
/*! /*!
@ -158,7 +168,7 @@ Model._getAccessTypeForMethod = function(method) {
'method is a required argument and must be a RemoteMethod object' 'method is a required argument and must be a RemoteMethod object'
); );
var ACL = getACL(); var ACL = Model._ACL();
switch(method.name) { switch(method.name) {
case'create': case'create':

View File

@ -9,35 +9,35 @@
"Platform", "Platform",
"mBaaS" "mBaaS"
], ],
"version": "1.6.1", "version": "1.6.2",
"scripts": { "scripts": {
"test": "mocha -R spec" "test": "mocha -R spec"
}, },
"dependencies": { "dependencies": {
"debug": "~0.7.2", "debug": "~0.7.4",
"express": "~3.4.0", "express": "~3.4.8",
"strong-remoting": "~1.2.1", "strong-remoting": "~1.2.4",
"inflection": "~1.2.5", "inflection": "~1.2.7",
"passport": "~0.1.17", "passport": "~0.2.0",
"passport-local": "~0.1.6", "passport-local": "~0.1.6",
"nodemailer": "~0.5.7", "nodemailer": "~0.6.0",
"ejs": "~0.8.4", "ejs": "~0.8.5",
"bcryptjs": "~0.7.10", "bcryptjs": "~0.7.10",
"underscore.string": "~2.3.3", "underscore.string": "~2.3.3",
"underscore": "~1.5.2", "underscore": "~1.6.0",
"uid2": "0.0.3", "uid2": "0.0.3",
"async": "~0.2.9" "async": "~0.2.10"
}, },
"peerDependencies": { "peerDependencies": {
"loopback-datasource-juggler": "~1.2.13" "loopback-datasource-juggler": "~1.3.0"
}, },
"devDependencies": { "devDependencies": {
"loopback-datasource-juggler": "~1.2.13", "loopback-datasource-juggler": "~1.3.0",
"mocha": "~1.14.0", "mocha": "~1.17.1",
"strong-task-emitter": "0.0.x", "strong-task-emitter": "0.0.x",
"supertest": "~0.8.1", "supertest": "~0.9.0",
"chai": "~1.8.1", "chai": "~1.9.0",
"loopback-testing": "~0.1.0" "loopback-testing": "~0.1.2"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -76,10 +76,17 @@ describe('app', function() {
}); });
}); });
describe('app.models', function() {
it('is unique per app instance', function() {
var Color = app.model('Color', { dataSource: 'db' });
expect(app.models.Color).to.equal(Color);
var anotherApp = loopback();
expect(anotherApp.models.Color).to.equal(undefined);
});
});
describe('app.boot([options])', function () { describe('app.boot([options])', function () {
beforeEach(function () { beforeEach(function () {
var app = this.app = loopback();
app.boot({ app.boot({
app: { app: {
port: 3000, port: 3000,
@ -393,6 +400,14 @@ describe('app', function() {
}); });
}); });
describe('enableAuth', function() {
it('should set app.isAuthEnabled to true', function() {
expect(app.isAuthEnabled).to.not.equal(true);
app.enableAuth();
expect(app.isAuthEnabled).to.equal(true);
});
});
describe('app.get("/", loopback.status())', function () { describe('app.get("/", loopback.status())', function () {
it('should return the status of the application', function (done) { it('should return the status of the application', function (done) {
var app = loopback(); var app = loopback();

View File

@ -121,7 +121,8 @@ describe('Application', function () {
it('Authenticate with application id & clientKey', function (done) { it('Authenticate with application id & clientKey', function (done) {
Application.authenticate(registeredApp.id, registeredApp.clientKey, Application.authenticate(registeredApp.id, registeredApp.clientKey,
function (err, result) { function (err, result) {
assert.equal(result, 'clientKey'); assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'clientKey');
done(err, result); done(err, result);
}); });
}); });
@ -129,7 +130,8 @@ describe('Application', function () {
it('Authenticate with application id & javaScriptKey', function (done) { it('Authenticate with application id & javaScriptKey', function (done) {
Application.authenticate(registeredApp.id, registeredApp.javaScriptKey, Application.authenticate(registeredApp.id, registeredApp.javaScriptKey,
function (err, result) { function (err, result) {
assert.equal(result, 'javaScriptKey'); assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'javaScriptKey');
done(err, result); done(err, result);
}); });
}); });
@ -137,7 +139,8 @@ describe('Application', function () {
it('Authenticate with application id & restApiKey', function (done) { it('Authenticate with application id & restApiKey', function (done) {
Application.authenticate(registeredApp.id, registeredApp.restApiKey, Application.authenticate(registeredApp.id, registeredApp.restApiKey,
function (err, result) { function (err, result) {
assert.equal(result, 'restApiKey'); assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'restApiKey');
done(err, result); done(err, result);
}); });
}); });
@ -145,7 +148,8 @@ describe('Application', function () {
it('Authenticate with application id & masterKey', function (done) { it('Authenticate with application id & masterKey', function (done) {
Application.authenticate(registeredApp.id, registeredApp.masterKey, Application.authenticate(registeredApp.id, registeredApp.masterKey,
function (err, result) { function (err, result) {
assert.equal(result, 'masterKey'); assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'masterKey');
done(err, result); done(err, result);
}); });
}); });
@ -153,7 +157,8 @@ describe('Application', function () {
it('Authenticate with application id & windowsKey', function (done) { it('Authenticate with application id & windowsKey', function (done) {
Application.authenticate(registeredApp.id, registeredApp.windowsKey, Application.authenticate(registeredApp.id, registeredApp.windowsKey,
function (err, result) { function (err, result) {
assert.equal(result, 'windowsKey'); assert.equal(result.application.id, registeredApp.id);
assert.equal(result.keyType, 'windowsKey');
done(err, result); done(err, result);
}); });
}); });
@ -170,13 +175,14 @@ describe('Application', function () {
describe('Application subclass', function () { describe('Application subclass', function () {
it('should use subclass model name', function (done) { it('should use subclass model name', function (done) {
var MyApp = Application.extend('MyApp'); var MyApp = Application.extend('MyApp');
MyApp.attachTo(loopback.createDataSource({connector: loopback.Memory})); var ds = loopback.createDataSource({connector: loopback.Memory});
MyApp.register('rfeng', 'MyApp2', MyApp.attachTo(ds);
{description: 'My second mobile application'}, function (err, result) { MyApp.register('rfeng', 'MyApp123',
{description: 'My 123 mobile application'}, function (err, result) {
var app = result; var app = result;
assert.equal(app.owner, 'rfeng'); assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp2'); assert.equal(app.name, 'MyApp123');
assert.equal(app.description, 'My second mobile application'); assert.equal(app.description, 'My 123 mobile application');
assert(app.clientKey); assert(app.clientKey);
assert(app.javaScriptKey); assert(app.javaScriptKey);
assert(app.restApiKey); assert(app.restApiKey);
@ -184,6 +190,8 @@ describe('Application subclass', function () {
assert(app.masterKey); assert(app.masterKey);
assert(app.created); assert(app.created);
assert(app.modified); assert(app.modified);
// Remove all instances from Application model to avoid left-over data
Application.destroyAll(function () {
MyApp.findById(app.id, function (err, myApp) { MyApp.findById(app.id, function (err, myApp) {
assert(!err); assert(!err);
assert(myApp); assert(myApp);
@ -196,5 +204,6 @@ describe('Application subclass', function () {
}); });
}); });
}); });
});
}); });

View File

@ -612,6 +612,16 @@ describe('Model', function() {
} }
}); });
describe('Model._getACLModel()', function() {
it('should return the subclass of ACL', function() {
var Model = require('../').Model;
var acl = ACL.extend('acl');
Model._ACL(null); // Reset the ACL class for the base model
var model = Model._ACL();
assert.equal(model, acl);
});
});
// describe('Model.hasAndBelongsToMany()', function() { // describe('Model.hasAndBelongsToMany()', function() {
// it("TODO: implement / document", function(done) { // it("TODO: implement / document", function(done) {
// /* example - // /* example -

View File

@ -17,7 +17,7 @@ request = require('supertest');
loopback.User.settings.saltWorkFactor = 4; loopback.User.settings.saltWorkFactor = 4;
beforeEach(function () { beforeEach(function () {
app = loopback(); this.app = app = loopback();
// setup default data sources // setup default data sources
loopback.setDefaultDataSourceForType('db', { loopback.setDefaultDataSourceForType('db', {