Merge pull request #105 from strongloop/feature/push-settings
Allow cert/key data to be shared by push/feedback
This commit is contained in:
commit
3652c1584a
|
@ -3,81 +3,93 @@ var assert = require('assert');
|
|||
|
||||
// Authentication schemes
|
||||
var AuthenticationSchemeSchema = {
|
||||
scheme: String, // local, facebook, google, twitter, linkedin, github
|
||||
credential: Object // Scheme-specific credentials
|
||||
scheme: String, // local, facebook, google, twitter, linkedin, github
|
||||
credential: Object // Scheme-specific credentials
|
||||
};
|
||||
|
||||
// See https://github.com/argon/node-apn/blob/master/doc/apn.markdown
|
||||
var APNSSettingSchema = {
|
||||
pushOptions: {type: {
|
||||
gateway: String,
|
||||
cert: String,
|
||||
key: String
|
||||
}},
|
||||
/**
|
||||
* production or development mode. It denotes what default APNS servers to be
|
||||
* used to send notifications
|
||||
* - true (production mode)
|
||||
* - push: gateway.push.apple.com:2195
|
||||
* - feedback: feedback.push.apple.com:2196
|
||||
* - false (development mode, the default)
|
||||
* - push: gateway.sandbox.push.apple.com:2195
|
||||
* - feedback: feedback.sandbox.push.apple.com:2196
|
||||
*/
|
||||
production: Boolean,
|
||||
certData: String, // The certificate data loaded from the cert.pem file
|
||||
keyData: String, // The key data loaded from the key.pem file
|
||||
|
||||
feedbackOptions: {type: {
|
||||
gateway: String,
|
||||
cert: String,
|
||||
key: String,
|
||||
batchFeedback: Boolean,
|
||||
interval: Number
|
||||
}}
|
||||
pushOptions: {type: {
|
||||
gateway: String,
|
||||
port: Number
|
||||
}},
|
||||
|
||||
feedbackOptions: {type: {
|
||||
gateway: String,
|
||||
port: Number,
|
||||
batchFeedback: Boolean,
|
||||
interval: Number
|
||||
}}
|
||||
};
|
||||
|
||||
var GcmSettingsSchema = {
|
||||
serverApiKey: String
|
||||
}
|
||||
};
|
||||
|
||||
// Push notification settings
|
||||
var PushNotificationSettingSchema = {
|
||||
apns: APNSSettingSchema,
|
||||
gcm: GcmSettingsSchema
|
||||
apns: APNSSettingSchema,
|
||||
gcm: GcmSettingsSchema
|
||||
};
|
||||
|
||||
/**
|
||||
* Data model for Application
|
||||
*/
|
||||
var ApplicationSchema = {
|
||||
id: {type: String, id: true, generated: true},
|
||||
// Basic information
|
||||
name: {type: String, required: true}, // The name
|
||||
description: String, // The description
|
||||
icon: String, // The icon image url
|
||||
id: {type: String, id: true, generated: true},
|
||||
// Basic information
|
||||
name: {type: String, required: true}, // The name
|
||||
description: String, // The description
|
||||
icon: String, // The icon image url
|
||||
|
||||
owner: String, // The user id of the developer who registers the application
|
||||
collaborators: [String], // A list of users ids who have permissions to work on this app
|
||||
owner: String, // The user id of the developer who registers the application
|
||||
collaborators: [String], // A list of users ids who have permissions to work on this app
|
||||
|
||||
// EMail
|
||||
email: String, // e-mail address
|
||||
emailVerified: Boolean, // Is the e-mail verified
|
||||
// EMail
|
||||
email: String, // e-mail address
|
||||
emailVerified: Boolean, // Is the e-mail verified
|
||||
|
||||
// oAuth 2.0 settings
|
||||
url: String, // The application url
|
||||
callbackUrls: [String], // oAuth 2.0 code/token callback url
|
||||
permissions: [String], // A list of permissions required by the application
|
||||
// oAuth 2.0 settings
|
||||
url: String, // The application url
|
||||
callbackUrls: [String], // oAuth 2.0 code/token callback url
|
||||
permissions: [String], // A list of permissions required by the application
|
||||
|
||||
// Keys
|
||||
clientKey: String,
|
||||
javaScriptKey: String,
|
||||
restApiKey: String,
|
||||
windowsKey: String,
|
||||
masterKey: String,
|
||||
// Keys
|
||||
clientKey: String,
|
||||
javaScriptKey: String,
|
||||
restApiKey: String,
|
||||
windowsKey: String,
|
||||
masterKey: String,
|
||||
|
||||
// Push notification
|
||||
pushSettings: PushNotificationSettingSchema,
|
||||
// Push notification
|
||||
pushSettings: PushNotificationSettingSchema,
|
||||
|
||||
// User Authentication
|
||||
authenticationEnabled: {type: Boolean, default: true},
|
||||
anonymousAllowed: {type: Boolean, default: true},
|
||||
authenticationSchemes: [AuthenticationSchemeSchema],
|
||||
// User Authentication
|
||||
authenticationEnabled: {type: Boolean, default: true},
|
||||
anonymousAllowed: {type: Boolean, default: true},
|
||||
authenticationSchemes: [AuthenticationSchemeSchema],
|
||||
|
||||
status: {type: String, default: 'sandbox'}, // Status of the application, production/sandbox/disabled
|
||||
status: {type: String, default: 'sandbox'}, // Status of the application, production/sandbox/disabled
|
||||
|
||||
// Timestamps
|
||||
created: {type: Date, default: Date},
|
||||
modified: {type: Date, default: Date}
|
||||
// Timestamps
|
||||
created: {type: Date, default: Date},
|
||||
modified: {type: Date, default: Date}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Application management functions
|
||||
*/
|
||||
|
@ -85,13 +97,13 @@ var ApplicationSchema = {
|
|||
var crypto = require('crypto');
|
||||
|
||||
function generateKey(hmacKey, algorithm, encoding) {
|
||||
hmacKey = hmacKey || 'loopback';
|
||||
algorithm = algorithm || 'sha256';
|
||||
encoding = encoding || 'base64';
|
||||
var hmac = crypto.createHmac(algorithm, hmacKey);
|
||||
var buf = crypto.randomBytes(64);
|
||||
hmac.update(buf);
|
||||
return hmac.digest('base64');
|
||||
hmacKey = hmacKey || 'loopback';
|
||||
algorithm = algorithm || 'sha256';
|
||||
encoding = encoding || 'base64';
|
||||
var hmac = crypto.createHmac(algorithm, hmacKey);
|
||||
var buf = crypto.randomBytes(64);
|
||||
hmac.update(buf);
|
||||
return hmac.digest('base64');
|
||||
}
|
||||
|
||||
var Application = loopback.createModel('Application', ApplicationSchema);
|
||||
|
@ -101,15 +113,15 @@ var Application = loopback.createModel('Application', ApplicationSchema);
|
|||
* @param next
|
||||
*/
|
||||
Application.beforeCreate = function (next) {
|
||||
var app = this;
|
||||
app.created = app.modified = new Date();
|
||||
app.id = generateKey('id', 'sha1');
|
||||
app.clientKey = generateKey('client');
|
||||
app.javaScriptKey = generateKey('javaScript');
|
||||
app.restApiKey = generateKey('restApi');
|
||||
app.windowsKey = generateKey('windows');
|
||||
app.masterKey = generateKey('master');
|
||||
next();
|
||||
var app = this;
|
||||
app.created = app.modified = new Date();
|
||||
app.id = generateKey('id', 'sha1');
|
||||
app.clientKey = generateKey('client');
|
||||
app.javaScriptKey = generateKey('javaScript');
|
||||
app.restApiKey = generateKey('restApi');
|
||||
app.windowsKey = generateKey('windows');
|
||||
app.masterKey = generateKey('master');
|
||||
next();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -120,34 +132,34 @@ Application.beforeCreate = function (next) {
|
|||
* @param cb Callback function
|
||||
*/
|
||||
Application.register = function (owner, name, options, cb) {
|
||||
assert(owner, 'owner is required');
|
||||
assert(name, 'name is required');
|
||||
assert(owner, 'owner is required');
|
||||
assert(name, 'name is required');
|
||||
|
||||
if(typeof options === 'function' && !cb) {
|
||||
cb = options;
|
||||
options = {};
|
||||
if (typeof options === 'function' && !cb) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
var props = {owner: owner, name: name};
|
||||
for (var p in options) {
|
||||
if (!(p in props)) {
|
||||
props[p] = options[p];
|
||||
}
|
||||
var props = {owner: owner, name: name};
|
||||
for(var p in options) {
|
||||
if(!(p in props)) {
|
||||
props[p] = options[p];
|
||||
}
|
||||
}
|
||||
Application.create(props, cb);
|
||||
}
|
||||
Application.create(props, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset keys for the application instance
|
||||
* @param cb
|
||||
*/
|
||||
Application.prototype.resetKeys = function(cb) {
|
||||
this.clientKey = generateKey('client');
|
||||
this.javaScriptKey = generateKey('javaScript');
|
||||
this.restApiKey = generateKey('restApi');
|
||||
this.windowsKey = generateKey('windows');
|
||||
this.masterKey = generateKey('master');
|
||||
this.modified = new Date();
|
||||
this.save(cb);
|
||||
Application.prototype.resetKeys = function (cb) {
|
||||
this.clientKey = generateKey('client');
|
||||
this.javaScriptKey = generateKey('javaScript');
|
||||
this.restApiKey = generateKey('restApi');
|
||||
this.windowsKey = generateKey('windows');
|
||||
this.masterKey = generateKey('master');
|
||||
this.modified = new Date();
|
||||
this.save(cb);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -155,14 +167,14 @@ Application.prototype.resetKeys = function(cb) {
|
|||
* @param appId
|
||||
* @param cb
|
||||
*/
|
||||
Application.resetKeys = function(appId, cb) {
|
||||
Application.findById(appId, function(err, app) {
|
||||
if(err) {
|
||||
cb && cb(err, app);
|
||||
return;
|
||||
}
|
||||
app.resetKeys(cb);
|
||||
});
|
||||
Application.resetKeys = function (appId, cb) {
|
||||
Application.findById(appId, function (err, app) {
|
||||
if (err) {
|
||||
cb && cb(err, app);
|
||||
return;
|
||||
}
|
||||
app.resetKeys(cb);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -171,20 +183,20 @@ Application.resetKeys = function(appId, cb) {
|
|||
* @param key
|
||||
* @param cb
|
||||
*/
|
||||
Application.authenticate = function(appId, key, cb) {
|
||||
Application.findById(appId, function(err, app) {
|
||||
if(err || !app) {
|
||||
cb && cb(err, null);
|
||||
return;
|
||||
}
|
||||
var matched = null;
|
||||
['clientKey', 'javaScriptKey', 'restApiKey', 'windowsKey', 'masterKey'].forEach(function(k) {
|
||||
if(app[k] === key) {
|
||||
matched = k;
|
||||
}
|
||||
});
|
||||
cb && cb(null, matched);
|
||||
Application.authenticate = function (appId, key, cb) {
|
||||
Application.findById(appId, function (err, app) {
|
||||
if (err || !app) {
|
||||
cb && cb(err, null);
|
||||
return;
|
||||
}
|
||||
var matched = null;
|
||||
['clientKey', 'javaScriptKey', 'restApiKey', 'windowsKey', 'masterKey'].forEach(function (k) {
|
||||
if (app[k] === key) {
|
||||
matched = k;
|
||||
}
|
||||
});
|
||||
cb && cb(null, matched);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Application;
|
||||
|
|
|
@ -3,109 +3,167 @@ var assert = require('assert');
|
|||
var Application = loopback.Application;
|
||||
|
||||
describe('Application', function () {
|
||||
var registeredApp = null;
|
||||
var registeredApp = null;
|
||||
|
||||
it('Create a new application', function (done) {
|
||||
Application.create({owner: 'rfeng', name: 'MyApp1', description: 'My first mobile application'}, function (err, result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp1');
|
||||
assert.equal(app.description, 'My first mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
done(err, result);
|
||||
});
|
||||
it('Create a new application', function (done) {
|
||||
Application.create({owner: 'rfeng',
|
||||
name: 'MyApp1',
|
||||
description: 'My first mobile application'}, function (err, result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp1');
|
||||
assert.equal(app.description, 'My first mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function (done) {
|
||||
Application.register('rfeng', 'MyApp2', {description: 'My second mobile application'}, function (err, result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp2');
|
||||
assert.equal(app.description, 'My second mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
registeredApp = app;
|
||||
done(err, result);
|
||||
it('Create a new application with push settings', function (done) {
|
||||
Application.create({owner: 'rfeng',
|
||||
name: 'MyAppWithPush',
|
||||
description: 'My push mobile application',
|
||||
pushSettings: {
|
||||
apns: {
|
||||
production: false,
|
||||
certData: 'cert',
|
||||
keyData: 'key',
|
||||
pushOptions: {
|
||||
gateway: 'gateway.sandbox.push.apple.com',
|
||||
port: 2195
|
||||
},
|
||||
feedbackOptions: {
|
||||
gateway: 'feedback.sandbox.push.apple.com',
|
||||
port: 2196,
|
||||
interval: 300,
|
||||
batchFeedback: true
|
||||
}
|
||||
},
|
||||
gcm: {
|
||||
serverApiKey: 'serverKey'
|
||||
}
|
||||
}},
|
||||
function (err, result) {
|
||||
var app = result;
|
||||
assert.deepEqual(app.pushSettings.toObject(), {
|
||||
apns: {
|
||||
production: false,
|
||||
certData: 'cert',
|
||||
keyData: 'key',
|
||||
pushOptions: {
|
||||
gateway: 'gateway.sandbox.push.apple.com',
|
||||
port: 2195
|
||||
},
|
||||
feedbackOptions: {
|
||||
gateway: 'feedback.sandbox.push.apple.com',
|
||||
port: 2196,
|
||||
interval: 300,
|
||||
batchFeedback: true
|
||||
}
|
||||
},
|
||||
gcm: {
|
||||
serverApiKey: 'serverKey'
|
||||
}
|
||||
});
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function (done) {
|
||||
Application.register('rfeng', 'MyApp2',
|
||||
{description: 'My second mobile application'}, function (err, result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp2');
|
||||
assert.equal(app.description, 'My second mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
registeredApp = app;
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
it('Reset keys', function (done) {
|
||||
Application.resetKeys(registeredApp.id, function (err, result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp2');
|
||||
assert.equal(app.description, 'My second mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
|
||||
assert(app.clientKey !== registeredApp.clientKey);
|
||||
assert(app.javaScriptKey !== registeredApp.javaScriptKey);
|
||||
assert(app.restApiKey !== registeredApp.restApiKey);
|
||||
assert(app.windowsKey !== registeredApp.windowsKey);
|
||||
assert(app.masterKey !== registeredApp.masterKey);
|
||||
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
registeredApp = app;
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
it('Reset keys', function (done) {
|
||||
Application.resetKeys(registeredApp.id, function (err, result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp2');
|
||||
assert.equal(app.description, 'My second mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
it('Authenticate with application id & clientKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.clientKey,
|
||||
function (err, result) {
|
||||
assert.equal(result, 'clientKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
assert(app.clientKey !== registeredApp.clientKey);
|
||||
assert(app.javaScriptKey !== registeredApp.javaScriptKey);
|
||||
assert(app.restApiKey !== registeredApp.restApiKey);
|
||||
assert(app.windowsKey !== registeredApp.windowsKey);
|
||||
assert(app.masterKey !== registeredApp.masterKey);
|
||||
it('Authenticate with application id & javaScriptKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.javaScriptKey,
|
||||
function (err, result) {
|
||||
assert.equal(result, 'javaScriptKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
registeredApp = app;
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
it('Authenticate with application id & restApiKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.restApiKey,
|
||||
function (err, result) {
|
||||
assert.equal(result, 'restApiKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
it('Authenticate with application id & clientKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.clientKey, function (err, result) {
|
||||
assert.equal(result, 'clientKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
it('Authenticate with application id & masterKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.masterKey,
|
||||
function (err, result) {
|
||||
assert.equal(result, 'masterKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
it('Authenticate with application id & javaScriptKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.javaScriptKey, function (err, result) {
|
||||
assert.equal(result, 'javaScriptKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
it('Authenticate with application id & windowsKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.windowsKey,
|
||||
function (err, result) {
|
||||
assert.equal(result, 'windowsKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
it('Authenticate with application id & restApiKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.restApiKey, function (err, result) {
|
||||
assert.equal(result, 'restApiKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
it('Authenticate with application id & masterKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.masterKey, function (err, result) {
|
||||
assert.equal(result, 'masterKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('Authenticate with application id & windowsKey', function (done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.windowsKey, function (err, result) {
|
||||
assert.equal(result, 'windowsKey');
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
it('Fail to authenticate with application id & invalid key', function (done) {
|
||||
Application.authenticate(registeredApp.id, 'invalid-key', function (err, result) {
|
||||
assert(!result);
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
it('Fail to authenticate with application id & invalid key', function (done) {
|
||||
Application.authenticate(registeredApp.id, 'invalid-key',
|
||||
function (err, result) {
|
||||
assert(!result);
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue