nitrogen-core
Version:
Core services used across ingestion, registry, and consumption servers.
151 lines (116 loc) • 4.89 kB
JavaScript
var async = require('async')
, core = require('../../lib')
, crypto = require('crypto')
, redis = require('redis');
var redisClient;
var assign = function(principal, callback) {
core.models.ApiKey.findOneAndUpdate({ owner: { $exists: false }, type: 'user' }, { $set: { owner: principal.id, name: 'User' } }, function(err, apiKey) {
if (err) return callback(err);
// regardless, create a new unassigned key.
createUnassigned();
// if we assigned a key, return that.
if (apiKey) return callback(null, apiKey);
var apiKey = new core.models.ApiKey({
name: 'User',
type: 'user',
owner: principal.id
});
// otherwise, no unassigned keys available, so create an assigned one directly.
create(core.services.principals.servicePrincipal, apiKey, callback);
});
};
var check = function(key, redirectUri, callback) {
if (!redirectUri) return callback(core.utils.badRequestError("redirect_uri " + key + " not provided."));
find({ key: key }, {}, function(err, apiKeys) {
if (err) return callback(err);
if (apiKeys.length === 0) return callback(core.utils.badRequestError("api_key " + key + " not found."));
var apiKey = apiKeys[0];
if (!apiKey.enabled) return callback(core.utils.authorizationError("api_key " + key + " is not enabled"));
if (!core.utils.stringStartsWith(redirectUri, apiKey.redirect_uri)) return callback(core.utils.badRequestError("redirect_uri does not match API Key."));
return callback(null, apiKey);
});
};
var create = function(authzPrincipal, apiKey, callback) {
var validType = false;
core.models.ApiKey.APIKEY_TYPES.forEach(function(type) {
validType = validType || apiKey.type === type;
});
if (!validType) {
var err = 'API key type invalid. found: ' + apiKey.type;
core.log.error(err);
return callback(core.utils.badRequestError(err));
}
if (!apiKey.redirect_uri && apiKey.type === 'app') {
var err = 'Redirect URI not provided and is required.';
core.log.error(err);
return callback(core.utils.badRequestError(err));
}
if (authzPrincipal !== core.services.principals.servicePrincipal)
apiKey.owner = authzPrincipal;
crypto.randomBytes(core.config.api_key_bytes, function(err, apiKeyBuf) {
if (err) return callback(err);
if (!apiKey.key)
apiKey.key = apiKeyBuf.toString('hex');
apiKey.save(function(err) {
if (callback) return callback(err, apiKey);
});
});
};
var createUnassigned = function(callback) {
core.log.info('apikeys service: creating unassigned key.');
core.services.apiKeys.create(core.services.principals.servicePrincipal, new core.models.ApiKey({ type: 'user', name: 'User' }), callback);
};
var createAdminKey = function(callback) {
core.log.info('apikeys service: creating unassigned key.');
core.services.apiKeys.create(core.services.principals.servicePrincipal, new core.models.ApiKey({
capabilities: ["impersonate"],
key: process.env.ADMIN_API_KEY,
name: 'Web Admin',
redirect_uri: process.env.ADMIN_REDIRECT_ROOT,
type: 'app'
}), callback);
};
var find = function(query, options, callback) {
core.models.ApiKey.find(query, null, options, callback);
};
var findById = function(id, callback) {
if (!id) return callback(null, undefined);
return core.models.ApiKey.findOne({ _id: id }, callback);
};
var findByKey = function(key, callback) {
if (!key) return callback(null, undefined);
return core.models.ApiKey.findOne({ key: key }, callback);
};
var initialize = function(callback) {
core.models.ApiKey.find({ owner: { $exists: false }, type: 'user' }, {}, function(err, apiKeys) {
if (err) return callback(err);
var required = core.config.unassigned_apikey_pool_size - apiKeys.length;
if (required > 0) {
async.times(required, function(n, next) {
createUnassigned(next);
}, callback);
} else {
return callback();
}
});
if (process.env.ADMIN_API_KEY && process.env.ADMIN_REDIRECT_ROOT) {
core.models.ApiKey.find({ name: process.env.ADMIN_API_KEY }, {}, function(err, apiKeys) {
if (err) return callback(err);
if (apiKeys.length !== 0) return callback();
createAdminKey(callback);
});
}
};
var remove = function(query, callback) {
core.models.ApiKey.remove(query, callback);
};
module.exports = {
assign: assign,
check: check,
create: create,
find: find,
findById: findById,
findByKey: findByKey,
initialize: initialize,
remove: remove,
};