228 lines
5.7 KiB
JavaScript
228 lines
5.7 KiB
JavaScript
var loopback = require('../loopback');
|
|
var assert = require('assert');
|
|
|
|
// Authentication schemes
|
|
var AuthenticationSchemeSchema = {
|
|
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 = {
|
|
/**
|
|
* 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
|
|
|
|
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
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
|
|
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
|
|
|
|
// 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,
|
|
|
|
// Push notification
|
|
pushSettings: PushNotificationSettingSchema,
|
|
|
|
// 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
|
|
|
|
// Timestamps
|
|
created: {type: Date, default: Date},
|
|
modified: {type: Date, default: Date}
|
|
};
|
|
|
|
/*!
|
|
* 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.
|
|
* @class
|
|
* @inherits {Model}
|
|
*/
|
|
|
|
var Application = loopback.createModel('Application', ApplicationSchema);
|
|
|
|
/*!
|
|
* A hook to generate keys before creation
|
|
* @param next
|
|
*/
|
|
Application.beforeCreate = function (next) {
|
|
var app = this;
|
|
app.created = app.modified = new Date();
|
|
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 owner Owner's user id
|
|
* @param name Name of the application
|
|
* @param options Other options
|
|
* @param cb 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 = {};
|
|
}
|
|
var props = {owner: owner, name: name};
|
|
for (var p in options) {
|
|
if (!(p in props)) {
|
|
props[p] = options[p];
|
|
}
|
|
}
|
|
this.create(props, cb);
|
|
};
|
|
|
|
/**
|
|
* 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) {
|
|
this.findById(appId, function (err, app) {
|
|
if (err) {
|
|
cb && cb(err, app);
|
|
return;
|
|
}
|
|
app.resetKeys(cb);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Authenticate the application id and key.
|
|
*
|
|
* `matched` parameter is one of:
|
|
* - clientKey
|
|
* - javaScriptKey
|
|
* - restApiKey
|
|
* - windowsKey
|
|
* - masterKey
|
|
*
|
|
* @param {Any} appId
|
|
* @param {String} key
|
|
* @callback {Function} callback
|
|
* @param {Error} err
|
|
* @param {String} matched The matching key
|
|
*/
|
|
Application.authenticate = function (appId, key, cb) {
|
|
this.findById(appId, function (err, app) {
|
|
if (err || !app) {
|
|
cb && cb(err, null);
|
|
return;
|
|
}
|
|
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 && cb(null, result);
|
|
});
|
|
};
|
|
|
|
module.exports = Application;
|
|
|