210 lines
6.9 KiB
JavaScript
210 lines
6.9 KiB
JavaScript
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
|
// Node module: loopback
|
|
// This file is licensed under the MIT License.
|
|
// License text available at https://opensource.org/licenses/MIT
|
|
|
|
var assert = require('assert');
|
|
var utils = require('../../lib/utils');
|
|
|
|
/*!
|
|
* Application management functions
|
|
*/
|
|
|
|
var crypto = require('crypto');
|
|
|
|
function generateKey(hmacKey, algorithm, encoding) {
|
|
hmacKey = hmacKey || 'loopback';
|
|
algorithm = algorithm || 'sha1';
|
|
encoding = encoding || 'hex';
|
|
var hmac = crypto.createHmac(algorithm, hmacKey);
|
|
var buf = crypto.randomBytes(32);
|
|
hmac.update(buf);
|
|
var key = hmac.digest(encoding);
|
|
return key;
|
|
}
|
|
|
|
/**
|
|
* Manage client applications and organize their users.
|
|
*
|
|
* @property {String} id Generated ID.
|
|
* @property {String} name Name; required.
|
|
* @property {String} description Text description
|
|
* @property {String} icon String Icon image URL.
|
|
* @property {String} owner User ID of the developer who registers the application.
|
|
* @property {String} email E-mail address
|
|
* @property {Boolean} emailVerified Whether the e-mail is verified.
|
|
* @property {String} url OAuth 2.0 application URL.
|
|
* @property {String}[] callbackUrls The OAuth 2.0 code/token callback URL.
|
|
* @property {String} status Status of the application; Either `production`, `sandbox` (default), or `disabled`.
|
|
* @property {Date} created Date Application object was created. Default: current date.
|
|
* @property {Date} modified Date Application object was modified. Default: current date.
|
|
*
|
|
* @property {Object} pushSettings.apns APNS configuration, see the options
|
|
* below and also
|
|
* https://github.com/argon/node-apn/blob/master/doc/apn.markdown
|
|
* @property {Boolean} pushSettings.apns.production Whether to use production Apple Push Notification Service (APNS) servers to send push notifications.
|
|
* If true, uses `gateway.push.apple.com:2195` and `feedback.push.apple.com:2196`.
|
|
* If false, uses `gateway.sandbox.push.apple.com:2195` and `feedback.sandbox.push.apple.com:2196`
|
|
* @property {String} pushSettings.apns.certData The certificate data loaded from the cert.pem file (APNS).
|
|
* @property {String} pushSettings.apns.keyData The key data loaded from the key.pem file (APNS).
|
|
* @property {String} pushSettings.apns.pushOptions.gateway (APNS).
|
|
* @property {Number} pushSettings.apns.pushOptions.port (APNS).
|
|
* @property {String} pushSettings.apns.feedbackOptions.gateway (APNS).
|
|
* @property {Number} pushSettings.apns.feedbackOptions.port (APNS).
|
|
* @property {Boolean} pushSettings.apns.feedbackOptions.batchFeedback (APNS).
|
|
* @property {Number} pushSettings.apns.feedbackOptions.interval (APNS).
|
|
* @property {String} pushSettings.gcm.serverApiKey: Google Cloud Messaging API key.
|
|
*
|
|
* @property {Boolean} authenticationEnabled
|
|
* @property {Boolean} anonymousAllowed
|
|
* @property {Array} authenticationSchemes List of authentication schemes
|
|
* (see below).
|
|
* @property {String} authenticationSchemes.scheme Scheme name.
|
|
* Supported values: `local`, `facebook`, `google`,
|
|
* `twitter`, `linkedin`, `github`.
|
|
* @property {Object} authenticationSchemes.credential
|
|
* Scheme-specific credentials.
|
|
*
|
|
* @class Application
|
|
* @inherits {PersistedModel}
|
|
*/
|
|
|
|
module.exports = function(Application) {
|
|
|
|
// Workaround for https://github.com/strongloop/loopback/issues/292
|
|
Application.definition.rawProperties.created.default =
|
|
Application.definition.properties.created.default = function() {
|
|
return new Date();
|
|
};
|
|
|
|
// Workaround for https://github.com/strongloop/loopback/issues/292
|
|
Application.definition.rawProperties.modified.default =
|
|
Application.definition.properties.modified.default = function() {
|
|
return new Date();
|
|
};
|
|
|
|
/*!
|
|
* A hook to generate keys before creation
|
|
* @param next
|
|
*/
|
|
Application.observe('before save', function(ctx, next) {
|
|
if (!ctx.instance) {
|
|
// Partial update - don't generate new keys
|
|
// NOTE(bajtos) This also means that an atomic updateOrCreate
|
|
// will not generate keys when a new record is creatd
|
|
return next();
|
|
}
|
|
|
|
var app = ctx.instance;
|
|
app.created = app.modified = new Date();
|
|
if (!app.id) {
|
|
app.id = generateKey('id', 'md5');
|
|
}
|
|
app.clientKey = generateKey('client');
|
|
app.javaScriptKey = generateKey('javaScript');
|
|
app.restApiKey = generateKey('restApi');
|
|
app.windowsKey = generateKey('windows');
|
|
app.masterKey = generateKey('master');
|
|
next();
|
|
});
|
|
|
|
/**
|
|
* Register a new application
|
|
* @param {String} owner Owner's user ID.
|
|
* @param {String} name Name of the application
|
|
* @param {Object} options Other options
|
|
* @param {Function} callback Callback function
|
|
*/
|
|
Application.register = function(owner, name, options, cb) {
|
|
assert(owner, 'owner is required');
|
|
assert(name, 'name is required');
|
|
|
|
if (typeof options === 'function' && !cb) {
|
|
cb = options;
|
|
options = {};
|
|
}
|
|
cb = cb || utils.createPromiseCallback();
|
|
|
|
var props = {owner: owner, name: name};
|
|
for (var p in options) {
|
|
if (!(p in props)) {
|
|
props[p] = options[p];
|
|
}
|
|
}
|
|
this.create(props, cb);
|
|
return cb.promise;
|
|
};
|
|
|
|
/**
|
|
* Reset keys for the application instance
|
|
* @callback {Function} callback
|
|
* @param {Error} err
|
|
*/
|
|
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);
|
|
};
|
|
|
|
/**
|
|
* Reset keys for a given application by the appId
|
|
* @param {Any} appId
|
|
* @callback {Function} callback
|
|
* @param {Error} err
|
|
*/
|
|
Application.resetKeys = function(appId, cb) {
|
|
cb = cb || utils.createPromiseCallback();
|
|
this.findById(appId, function(err, app) {
|
|
if (err) {
|
|
if (cb) cb(err, app);
|
|
return;
|
|
}
|
|
app.resetKeys(cb);
|
|
});
|
|
return cb.promise;
|
|
};
|
|
|
|
/**
|
|
* Authenticate the application id and key.
|
|
*
|
|
* @param {Any} appId
|
|
* @param {String} key
|
|
* @callback {Function} callback
|
|
* @param {Error} err
|
|
* @param {String} matched The matching key; one of:
|
|
* - clientKey
|
|
* - javaScriptKey
|
|
* - restApiKey
|
|
* - windowsKey
|
|
* - masterKey
|
|
*
|
|
*/
|
|
Application.authenticate = function(appId, key, cb) {
|
|
cb = cb || utils.createPromiseCallback();
|
|
|
|
this.findById(appId, function(err, app) {
|
|
if (err || !app) {
|
|
cb(err, null);
|
|
return cb.promise;
|
|
}
|
|
var result = null;
|
|
var keyNames = ['clientKey', 'javaScriptKey', 'restApiKey', 'windowsKey', 'masterKey'];
|
|
for (var i = 0; i < keyNames.length; i++) {
|
|
if (app[keyNames[i]] === key) {
|
|
result = {
|
|
application: app,
|
|
keyType: keyNames[i]
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
cb(null, result);
|
|
});
|
|
return cb.promise;
|
|
};
|
|
};
|