Remove Oauth clients code
This commit is contained in:
+5
-29
@@ -29,13 +29,11 @@ exports = module.exports = {
|
||||
SERVICE_STATUS_STOPPED: 'stopped'
|
||||
};
|
||||
|
||||
var accesscontrol = require('./accesscontrol.js'),
|
||||
appdb = require('./appdb.js'),
|
||||
var appdb = require('./appdb.js'),
|
||||
apps = require('./apps.js'),
|
||||
assert = require('assert'),
|
||||
async = require('async'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
clients = require('./clients.js'),
|
||||
constants = require('./constants.js'),
|
||||
crypto = require('crypto'),
|
||||
debug = require('debug')('box:addons'),
|
||||
@@ -777,29 +775,11 @@ function setupOauth(app, options, callback) {
|
||||
|
||||
if (!app.sso) return callback(null);
|
||||
|
||||
var appId = app.id;
|
||||
var redirectURI = 'https://' + app.fqdn;
|
||||
var scope = accesscontrol.SCOPE_PROFILE;
|
||||
const env = [];
|
||||
|
||||
clients.delByAppIdAndType(appId, clients.TYPE_OAUTH, function (error) { // remove existing creds
|
||||
if (error && error.reason !== BoxError.NOT_FOUND) return callback(error);
|
||||
debugApp(app, 'Setting oauth addon config to %j', env);
|
||||
|
||||
clients.add(appId, clients.TYPE_OAUTH, redirectURI, scope, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
const envPrefix = app.manifest.manifestVersion <= 1 ? '' : 'CLOUDRON_';
|
||||
|
||||
var env = [
|
||||
{ name: `${envPrefix}OAUTH_CLIENT_ID`, value: result.id },
|
||||
{ name: `${envPrefix}OAUTH_CLIENT_SECRET`, value: result.clientSecret },
|
||||
{ name: `${envPrefix}OAUTH_ORIGIN`, value: settings.adminOrigin() }
|
||||
];
|
||||
|
||||
debugApp(app, 'Setting oauth addon config to %j', env);
|
||||
|
||||
appdb.setAddonConfig(appId, 'oauth', env, callback);
|
||||
});
|
||||
});
|
||||
appdb.setAddonConfig(app.id, 'oauth', env, callback);
|
||||
}
|
||||
|
||||
function teardownOauth(app, options, callback) {
|
||||
@@ -809,11 +789,7 @@ function teardownOauth(app, options, callback) {
|
||||
|
||||
debugApp(app, 'teardownOauth');
|
||||
|
||||
clients.delByAppIdAndType(app.id, clients.TYPE_OAUTH, function (error) {
|
||||
if (error && error.reason !== BoxError.NOT_FOUND) debug(error);
|
||||
|
||||
appdb.unsetAddonConfig(app.id, 'oauth', callback);
|
||||
});
|
||||
appdb.unsetAddonConfig(app.id, 'oauth', callback);
|
||||
}
|
||||
|
||||
function setupEmail(app, options, callback) {
|
||||
|
||||
-179
@@ -1,179 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
get: get,
|
||||
getAll: getAll,
|
||||
getAllWithTokenCount: getAllWithTokenCount,
|
||||
getAllWithTokenCountByIdentifier: getAllWithTokenCountByIdentifier,
|
||||
add: add,
|
||||
del: del,
|
||||
getByAppId: getByAppId,
|
||||
getByAppIdAndType: getByAppIdAndType,
|
||||
|
||||
upsert: upsert,
|
||||
|
||||
delByAppId: delByAppId,
|
||||
delByAppIdAndType: delByAppIdAndType,
|
||||
|
||||
_clear: clear
|
||||
};
|
||||
|
||||
var assert = require('assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
database = require('./database.js');
|
||||
|
||||
var CLIENTS_FIELDS = [ 'id', 'appId', 'type', 'clientSecret', 'redirectURI', 'scope' ].join(',');
|
||||
var CLIENTS_FIELDS_PREFIXED = [ 'clients.id', 'clients.appId', 'clients.type', 'clients.clientSecret', 'clients.redirectURI', 'clients.scope' ].join(',');
|
||||
|
||||
function get(id, callback) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + CLIENTS_FIELDS + ' FROM clients WHERE id = ?', [ id ], function (error, result) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, `Client not found: ${id}`));
|
||||
|
||||
callback(null, result[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function getAll(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + CLIENTS_FIELDS + ' FROM clients ORDER BY appId', function (error, results) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
|
||||
callback(null, results);
|
||||
});
|
||||
}
|
||||
|
||||
function getAllWithTokenCount(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + CLIENTS_FIELDS_PREFIXED + ',COUNT(tokens.clientId) AS tokenCount FROM clients LEFT OUTER JOIN tokens ON clients.id=tokens.clientId GROUP BY clients.id', [], function (error, results) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
|
||||
callback(null, results);
|
||||
});
|
||||
}
|
||||
|
||||
function getAllWithTokenCountByIdentifier(identifier, callback) {
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + CLIENTS_FIELDS_PREFIXED + ',COUNT(tokens.clientId) AS tokenCount FROM clients LEFT OUTER JOIN tokens ON clients.id=tokens.clientId WHERE tokens.identifier=? GROUP BY clients.id', [ identifier ], function (error, results) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
|
||||
callback(null, results);
|
||||
});
|
||||
}
|
||||
|
||||
function getByAppId(appId, callback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + CLIENTS_FIELDS + ' FROM clients WHERE appId = ? LIMIT 1', [ appId ], function (error, result) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'Client not found'));
|
||||
|
||||
callback(null, result[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function getByAppIdAndType(appId, type, callback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + CLIENTS_FIELDS + ' FROM clients WHERE appId = ? AND type = ? LIMIT 1', [ appId, type ], function (error, result) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'Client not found'));
|
||||
|
||||
callback(null, result[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function add(id, appId, type, clientSecret, redirectURI, scope, callback) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
assert.strictEqual(typeof clientSecret, 'string');
|
||||
assert.strictEqual(typeof redirectURI, 'string');
|
||||
assert.strictEqual(typeof scope, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
var data = [ id, appId, type, clientSecret, redirectURI, scope ];
|
||||
|
||||
database.query('INSERT INTO clients (id, appId, type, clientSecret, redirectURI, scope) VALUES (?, ?, ?, ?, ?, ?)', data, function (error, result) {
|
||||
if (error && error.code === 'ER_DUP_ENTRY') return callback(new BoxError(BoxError.ALREADY_EXISTS));
|
||||
if (error || result.affectedRows === 0) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function upsert(id, appId, type, clientSecret, redirectURI, scope, callback) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
assert.strictEqual(typeof clientSecret, 'string');
|
||||
assert.strictEqual(typeof redirectURI, 'string');
|
||||
assert.strictEqual(typeof scope, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
var data = [ id, appId, type, clientSecret, redirectURI, scope ];
|
||||
|
||||
database.query('REPLACE INTO clients (id, appId, type, clientSecret, redirectURI, scope) VALUES (?, ?, ?, ?, ?, ?)', data, function (error, result) {
|
||||
if (error && error.code === 'ER_DUP_ENTRY') return callback(new BoxError(BoxError.ALREADY_EXISTS));
|
||||
if (error || result.affectedRows === 0) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function del(id, callback) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('DELETE FROM clients WHERE id = ?', [ id ], function (error, result) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
if (result.affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, `Client not found: ${id}`));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function delByAppId(appId, callback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('DELETE FROM clients WHERE appId=?', [ appId ], function (error, result) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
if (result.affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, 'Client not found'));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function delByAppIdAndType(appId, type, callback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('DELETE FROM clients WHERE appId=? AND type=?', [ appId, type ], function (error, result) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
if (result.affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, 'Client not found'));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function clear(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('DELETE FROM clients', function (error) {
|
||||
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
-329
@@ -1,329 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
add: add,
|
||||
get: get,
|
||||
del: del,
|
||||
getAll: getAll,
|
||||
getByAppIdAndType: getByAppIdAndType,
|
||||
getTokensByUserId: getTokensByUserId,
|
||||
delTokensByUserId: delTokensByUserId,
|
||||
delByAppIdAndType: delByAppIdAndType,
|
||||
addTokenByUserId: addTokenByUserId,
|
||||
delToken: delToken,
|
||||
|
||||
issueDeveloperToken: issueDeveloperToken,
|
||||
|
||||
addDefaultClients: addDefaultClients,
|
||||
|
||||
removeTokenPrivateFields: removeTokenPrivateFields,
|
||||
|
||||
// client ids. we categorize them so we can have different restrictions based on the client
|
||||
ID_WEBADMIN: 'cid-webadmin', // dashboard oauth
|
||||
ID_SDK: 'cid-sdk', // created by user via dashboard
|
||||
ID_CLI: 'cid-cli', // created via cli tool
|
||||
|
||||
// client type enums
|
||||
TYPE_EXTERNAL: 'external',
|
||||
TYPE_BUILT_IN: 'built-in',
|
||||
TYPE_OAUTH: 'addon-oauth',
|
||||
TYPE_PROXY: 'addon-proxy'
|
||||
};
|
||||
|
||||
var apps = require('./apps.js'),
|
||||
assert = require('assert'),
|
||||
async = require('async'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
clientdb = require('./clientdb.js'),
|
||||
constants = require('./constants.js'),
|
||||
debug = require('debug')('box:clients'),
|
||||
eventlog = require('./eventlog.js'),
|
||||
hat = require('./hat.js'),
|
||||
accesscontrol = require('./accesscontrol.js'),
|
||||
tokendb = require('./tokendb.js'),
|
||||
users = require('./users.js'),
|
||||
uuid = require('uuid'),
|
||||
_ = require('underscore');
|
||||
|
||||
function validateClientName(name) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
|
||||
if (name.length < 1) return new BoxError(BoxError.BAD_FIELD, 'name must be atleast 1 character', { field: 'name' });
|
||||
if (name.length > 128) return new BoxError(BoxError.BAD_FIELD, 'name too long', { field: 'name' });
|
||||
|
||||
if (/[^a-zA-Z0-9-]/.test(name)) return new BoxError(BoxError.BAD_FIELD, 'name can only contain alphanumerals and dash', { field: 'name' });
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateTokenName(name) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
|
||||
if (name.length > 64) return new BoxError(BoxError.BAD_FIELD, 'name too long', { field: 'name' });
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function add(appId, type, redirectURI, scope, callback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
assert.strictEqual(typeof redirectURI, 'string');
|
||||
assert.strictEqual(typeof scope, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
var error = accesscontrol.validateScopeString(scope);
|
||||
if (error) return callback(error);
|
||||
|
||||
error = validateClientName(appId);
|
||||
if (error) return callback(error);
|
||||
|
||||
var id = 'cid-' + uuid.v4();
|
||||
var clientSecret = hat(8 * 128);
|
||||
|
||||
clientdb.add(id, appId, type, clientSecret, redirectURI, scope, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
var client = {
|
||||
id: id,
|
||||
appId: appId,
|
||||
type: type,
|
||||
clientSecret: clientSecret,
|
||||
redirectURI: redirectURI,
|
||||
scope: scope
|
||||
};
|
||||
|
||||
callback(null, client);
|
||||
});
|
||||
}
|
||||
|
||||
function get(id, callback) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
clientdb.get(id, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
|
||||
function del(id, callback) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
clientdb.del(id, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
|
||||
function getAll(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
clientdb.getAll(function (error, results) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, []);
|
||||
if (error) return callback(error);
|
||||
|
||||
var tmp = [];
|
||||
async.each(results, function (record, callback) {
|
||||
if (record.type === exports.TYPE_EXTERNAL || record.type === exports.TYPE_BUILT_IN) {
|
||||
// the appId in this case holds the name
|
||||
record.name = record.appId;
|
||||
|
||||
tmp.push(record);
|
||||
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
apps.get(record.appId, function (error, result) {
|
||||
if (error) {
|
||||
console.error('Failed to get app details for oauth client', record.appId, error);
|
||||
return callback(null); // ignore error so we continue listing clients
|
||||
}
|
||||
|
||||
if (record.type === exports.TYPE_PROXY) record.name = result.manifest.title + ' Website Proxy';
|
||||
if (record.type === exports.TYPE_OAUTH) record.name = result.manifest.title + ' OAuth';
|
||||
|
||||
record.domain = result.fqdn;
|
||||
|
||||
tmp.push(record);
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}, function (error) {
|
||||
if (error) return callback(error);
|
||||
callback(null, tmp);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getByAppIdAndType(appId, type, callback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
clientdb.getByAppIdAndType(appId, type, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
|
||||
function getTokensByUserId(clientId, userId, callback) {
|
||||
assert.strictEqual(typeof clientId, 'string');
|
||||
assert.strictEqual(typeof userId, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
tokendb.getByIdentifierAndClientId(userId, clientId, function (error, result) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) {
|
||||
// this can mean either that there are no tokens or the clientId is actually unknown
|
||||
get(clientId, function (error/*, result*/) {
|
||||
if (error) return callback(error);
|
||||
callback(null, []);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (error) return callback(error);
|
||||
callback(null, result || []);
|
||||
});
|
||||
}
|
||||
|
||||
function delTokensByUserId(clientId, userId, callback) {
|
||||
assert.strictEqual(typeof clientId, 'string');
|
||||
assert.strictEqual(typeof userId, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
tokendb.delByIdentifierAndClientId(userId, clientId, function (error) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) {
|
||||
// this can mean either that there are no tokens or the clientId is actually unknown
|
||||
get(clientId, function (error/*, result*/) {
|
||||
if (error) return callback(error);
|
||||
callback(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (error) return callback(error);
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function delByAppIdAndType(appId, type, callback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
getByAppIdAndType(appId, type, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
tokendb.delByClientId(result.id, function (error) {
|
||||
if (error && error.reason !== BoxError.NOT_FOUND) return callback(error);
|
||||
|
||||
clientdb.delByAppIdAndType(appId, type, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addTokenByUserId(clientId, userId, expiresAt, options, callback) {
|
||||
assert.strictEqual(typeof clientId, 'string');
|
||||
assert.strictEqual(typeof userId, 'string');
|
||||
assert.strictEqual(typeof expiresAt, 'number');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
const name = options.name || '';
|
||||
let error = validateTokenName(name);
|
||||
if (error) return callback(error);
|
||||
|
||||
get(clientId, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
users.get(userId, function (error, user) {
|
||||
if (error) return callback(error);
|
||||
|
||||
accesscontrol.scopesForUser(user, function (error, userScopes) {
|
||||
if (error) return callback(error);
|
||||
|
||||
const scope = accesscontrol.canonicalScopeString(result.scope);
|
||||
const authorizedScopes = accesscontrol.intersectScopes(userScopes, scope.split(','));
|
||||
|
||||
const token = {
|
||||
id: 'tid-' + uuid.v4(),
|
||||
accessToken: hat(8 * 32),
|
||||
identifier: userId,
|
||||
clientId: result.id,
|
||||
expires: expiresAt,
|
||||
scope: authorizedScopes.join(','),
|
||||
name: name
|
||||
};
|
||||
|
||||
tokendb.add(token, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null, {
|
||||
accessToken: token.accessToken,
|
||||
tokenScopes: authorizedScopes,
|
||||
identifier: userId,
|
||||
clientId: result.id,
|
||||
expires: expiresAt
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function issueDeveloperToken(userObject, auditSource, callback) {
|
||||
assert.strictEqual(typeof userObject, 'object');
|
||||
assert.strictEqual(typeof auditSource, 'object');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
const expiresAt = Date.now() + (30 * 24 * 60 * 60 * 1000); // cli tokens are valid for a month
|
||||
|
||||
addTokenByUserId(exports.ID_CLI, userObject.id, expiresAt, {}, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
eventlog.add(eventlog.ACTION_USER_LOGIN, auditSource, { userId: userObject.id, user: users.removePrivateFields(userObject) });
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
|
||||
function delToken(clientId, tokenId, callback) {
|
||||
assert.strictEqual(typeof clientId, 'string');
|
||||
assert.strictEqual(typeof tokenId, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
get(clientId, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
tokendb.del(tokenId, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addDefaultClients(origin, callback) {
|
||||
assert.strictEqual(typeof origin, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
debug('Adding default clients');
|
||||
|
||||
// The domain might have changed, therefor we have to update the record
|
||||
// id, appId, type, clientSecret, redirectURI, scope
|
||||
async.series([
|
||||
clientdb.upsert.bind(null, exports.ID_WEBADMIN, 'Settings', 'built-in', 'secret-webadmin', origin, '*'),
|
||||
clientdb.upsert.bind(null, exports.ID_SDK, 'SDK', 'built-in', 'secret-sdk', origin, '*'),
|
||||
clientdb.upsert.bind(null, exports.ID_CLI, 'Cloudron Tool', 'built-in', 'secret-cli', origin, '*')
|
||||
], callback);
|
||||
}
|
||||
|
||||
function removeTokenPrivateFields(token) {
|
||||
return _.pick(token, 'id', 'identifier', 'clientId', 'scope', 'expires', 'name');
|
||||
}
|
||||
+1
-5
@@ -27,7 +27,6 @@ var apps = require('./apps.js'),
|
||||
auditSource = require('./auditsource.js'),
|
||||
backups = require('./backups.js'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
clients = require('./clients.js'),
|
||||
constants = require('./constants.js'),
|
||||
cron = require('./cron.js'),
|
||||
debug = require('debug')('box:cloudron'),
|
||||
@@ -288,10 +287,7 @@ function setDashboardDomain(domain, auditSource, callback) {
|
||||
|
||||
const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject);
|
||||
|
||||
async.series([
|
||||
(done) => settings.setAdmin(domain, fqdn, done),
|
||||
(done) => clients.addDefaultClients(settings.adminOrigin(), done)
|
||||
], function (error) {
|
||||
settings.setAdmin(domain, fqdn, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
eventlog.add(eventlog.ACTION_DASHBOARD_DOMAIN_UPDATE, auditSource, { domain: domain, fqdn: fqdn });
|
||||
|
||||
+1
-4
@@ -104,10 +104,7 @@ function clear(callback) {
|
||||
gDatabase.hostname, gDatabase.username, gDatabase.password, gDatabase.name,
|
||||
gDatabase.hostname, gDatabase.username, gDatabase.password, gDatabase.name);
|
||||
|
||||
async.series([
|
||||
child_process.exec.bind(null, cmd),
|
||||
require('./clients.js').addDefaultClients.bind(null, 'https://admin-localhost')
|
||||
], callback);
|
||||
child_process.exec(cmd, callback);
|
||||
}
|
||||
|
||||
function beginTransaction(callback) {
|
||||
|
||||
+2
-2
@@ -15,7 +15,6 @@ var appstore = require('./appstore.js'),
|
||||
backups = require('./backups.js'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
constants = require('./constants.js'),
|
||||
clients = require('./clients.js'),
|
||||
cloudron = require('./cloudron.js'),
|
||||
debug = require('debug')('box:provision'),
|
||||
domains = require('./domains.js'),
|
||||
@@ -29,6 +28,7 @@ var appstore = require('./appstore.js'),
|
||||
sysinfo = require('./sysinfo.js'),
|
||||
users = require('./users.js'),
|
||||
tld = require('tldjs'),
|
||||
tokens = require('./tokens.js'),
|
||||
_ = require('underscore');
|
||||
|
||||
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
|
||||
@@ -165,7 +165,7 @@ function activate(username, password, email, displayName, ip, auditSource, callb
|
||||
if (error && error.reason === BoxError.ALREADY_EXISTS) return callback(new BoxError(BoxError.CONFLICT, 'Already activated'));
|
||||
if (error) return callback(error);
|
||||
|
||||
clients.addTokenByUserId('cid-webadmin', userObject.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
tokens.addTokenByUserId(tokens.ID_WEBADMIN, userObject.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
eventlog.add(eventlog.ACTION_ACTIVATE, auditSource, { });
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
add: add,
|
||||
get: get,
|
||||
del: del,
|
||||
getAll: getAll,
|
||||
addToken: addToken,
|
||||
getTokens: getTokens,
|
||||
delTokens: delTokens,
|
||||
delToken: delToken
|
||||
};
|
||||
|
||||
var assert = require('assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
clients = require('../clients.js'),
|
||||
constants = require('../constants.js'),
|
||||
HttpError = require('connect-lastmile').HttpError,
|
||||
HttpSuccess = require('connect-lastmile').HttpSuccess,
|
||||
validUrl = require('valid-url');
|
||||
|
||||
function add(req, res, next) {
|
||||
var data = req.body;
|
||||
|
||||
if (!data) return next(new HttpError(400, 'Cannot parse data field'));
|
||||
if (typeof data.appId !== 'string' || !data.appId) return next(new HttpError(400, 'appId is required'));
|
||||
if (typeof data.redirectURI !== 'string' || !data.redirectURI) return next(new HttpError(400, 'redirectURI is required'));
|
||||
if (typeof data.scope !== 'string' || !data.scope) return next(new HttpError(400, 'scope is required'));
|
||||
if (!validUrl.isWebUri(data.redirectURI)) return next(new HttpError(400, 'redirectURI must be a valid uri'));
|
||||
|
||||
clients.add(data.appId, clients.TYPE_EXTERNAL, data.redirectURI, data.scope, function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(201, result));
|
||||
});
|
||||
}
|
||||
|
||||
function get(req, res, next) {
|
||||
assert.strictEqual(typeof req.params.clientId, 'string');
|
||||
|
||||
clients.get(req.params.clientId, function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(200, result));
|
||||
});
|
||||
}
|
||||
|
||||
function del(req, res, next) {
|
||||
assert.strictEqual(typeof req.params.clientId, 'string');
|
||||
|
||||
clients.get(req.params.clientId, function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
// we do not allow to use the REST API to delete addon clients
|
||||
if (result.type !== clients.TYPE_EXTERNAL) return next(new HttpError(405, 'Deleting app addon clients is not allowed.'));
|
||||
|
||||
clients.del(req.params.clientId, function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(204, result));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getAll(req, res, next) {
|
||||
clients.getAll(function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(200, { clients: result }));
|
||||
});
|
||||
}
|
||||
|
||||
function addToken(req, res, next) {
|
||||
assert.strictEqual(typeof req.params.clientId, 'string');
|
||||
assert.strictEqual(typeof req.user, 'object');
|
||||
assert.strictEqual(typeof req.body, 'object');
|
||||
|
||||
var data = req.body;
|
||||
var expiresAt = data.expiresAt ? parseInt(data.expiresAt, 10) : Date.now() + constants.DEFAULT_TOKEN_EXPIRATION;
|
||||
if (isNaN(expiresAt) || expiresAt <= Date.now()) return next(new HttpError(400, 'expiresAt must be a timestamp in the future'));
|
||||
if ('name' in req.body && typeof req.body.name !== 'string') return next(new HttpError(400, 'name must be a string'));
|
||||
|
||||
clients.addTokenByUserId(req.params.clientId, req.user.id, expiresAt, { name: req.body.name || '' }, function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(201, { token: result }));
|
||||
});
|
||||
}
|
||||
|
||||
function getTokens(req, res, next) {
|
||||
assert.strictEqual(typeof req.params.clientId, 'string');
|
||||
assert.strictEqual(typeof req.user, 'object');
|
||||
|
||||
clients.getTokensByUserId(req.params.clientId, req.user.id, function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
result = result.map(clients.removeTokenPrivateFields);
|
||||
|
||||
next(new HttpSuccess(200, { tokens: result }));
|
||||
});
|
||||
}
|
||||
|
||||
function delTokens(req, res, next) {
|
||||
assert.strictEqual(typeof req.params.clientId, 'string');
|
||||
assert.strictEqual(typeof req.user, 'object');
|
||||
|
||||
clients.delTokensByUserId(req.params.clientId, req.user.id, function (error) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(204));
|
||||
});
|
||||
}
|
||||
|
||||
function delToken(req, res, next) {
|
||||
assert.strictEqual(typeof req.params.clientId, 'string');
|
||||
assert.strictEqual(typeof req.params.tokenId, 'string');
|
||||
assert.strictEqual(typeof req.user, 'object');
|
||||
|
||||
clients.delToken(req.params.clientId, req.params.tokenId, function (error) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(204));
|
||||
});
|
||||
}
|
||||
@@ -27,7 +27,6 @@ let assert = require('assert'),
|
||||
async = require('async'),
|
||||
auditSource = require('../auditsource.js'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
clients = require('../clients.js'),
|
||||
cloudron = require('../cloudron.js'),
|
||||
constants = require('../constants.js'),
|
||||
debug = require('debug')('box:routes/cloudron'),
|
||||
@@ -38,6 +37,7 @@ let assert = require('assert'),
|
||||
sysinfo = require('../sysinfo.js'),
|
||||
system = require('../system.js'),
|
||||
tokendb = require('../tokendb.js'),
|
||||
tokens = require('../tokens.js'),
|
||||
updater = require('../updater.js'),
|
||||
users = require('../users.js'),
|
||||
updateChecker = require('../updatechecker.js');
|
||||
@@ -48,7 +48,7 @@ function login(req, res, next) {
|
||||
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || null;
|
||||
const auditSource = { authType: 'basic', ip: ip };
|
||||
|
||||
clients.addTokenByUserId(clients.ID_WEBADMIN, req.user.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
tokens.addTokenByUserId(tokens.ID_WEBADMIN, req.user.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
if (error) return next(new HttpError(500, error));
|
||||
|
||||
eventlog.add(eventlog.ACTION_USER_LOGIN, auditSource, { userId: req.user.id, user: users.removePrivateFields(req.user) });
|
||||
@@ -104,7 +104,7 @@ function passwordReset(req, res, next) {
|
||||
if (error && error.reason === BoxError.BAD_FIELD) return next(new HttpError(406, error.message));
|
||||
if (error) return next(new HttpError(500, error));
|
||||
|
||||
clients.addTokenByUserId('cid-webadmin', userObject.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
tokens.addTokenByUserId(tokens.ID_WEBADMIN, userObject.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
if (error) return next(new HttpError(500, error));
|
||||
|
||||
next(new HttpSuccess(202, { accessToken: result.accessToken }));
|
||||
@@ -141,7 +141,7 @@ function setupAccount(req, res, next) {
|
||||
if (error && error.reason === BoxError.BAD_FIELD) return next(new HttpError(400, error.message));
|
||||
if (error) return next(new HttpError(500, error));
|
||||
|
||||
clients.addTokenByUserId(clients.ID_WEBADMIN, userObject.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
tokens.addTokenByUserId(tokens.ID_WEBADMIN, userObject.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) {
|
||||
if (error) return next(new HttpError(500, error));
|
||||
|
||||
next(new HttpSuccess(201, { accessToken: result.accessToken }));
|
||||
|
||||
@@ -6,7 +6,6 @@ exports = module.exports = {
|
||||
apps: require('./apps.js'),
|
||||
appstore: require('./appstore.js'),
|
||||
backups: require('./backups.js'),
|
||||
clients: require('./clients.js'),
|
||||
cloudron: require('./cloudron.js'),
|
||||
domains: require('./domains.js'),
|
||||
eventlog: require('./eventlog.js'),
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
let apps = require('../../apps.js'),
|
||||
async = require('async'),
|
||||
child_process = require('child_process'),
|
||||
clients = require('../../clients.js'),
|
||||
constants = require('../../constants.js'),
|
||||
crypto = require('crypto'),
|
||||
database = require('../../database.js'),
|
||||
@@ -29,6 +28,7 @@ let apps = require('../../apps.js'),
|
||||
settingsdb = require('../../settingsdb.js'),
|
||||
superagent = require('superagent'),
|
||||
tokendb = require('../../tokendb.js'),
|
||||
tokens = require('../../tokens.js'),
|
||||
url = require('url');
|
||||
|
||||
var SERVER_URL = 'http://localhost:' + constants.PORT;
|
||||
@@ -213,7 +213,7 @@ function startBox(done) {
|
||||
token_1 = hat(8 * 32);
|
||||
|
||||
// HACK to get a token for second user (passwords are generated and the user should have gotten a password setup link...)
|
||||
tokendb.add({ id: 'tid-1', accessToken: token_1, identifier: user_1_id, clientId: clients.ID_SDK, expires: Date.now() + 1000000, scope: 'apps', name: '' }, callback);
|
||||
tokendb.add({ id: 'tid-1', accessToken: token_1, identifier: user_1_id, clientId: tokens.ID_SDK, expires: Date.now() + 1000000, scope: 'apps', name: '' }, callback);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -633,22 +633,6 @@ describe('App API', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('oauth addon config', function (done) {
|
||||
var appContainer = docker.getContainer(appEntry.containerId);
|
||||
appContainer.inspect(function (error, data) {
|
||||
expect(error).to.not.be.ok();
|
||||
|
||||
clients.getByAppIdAndType(APP_ID, clients.TYPE_OAUTH, function (error, client) {
|
||||
expect(error).to.not.be.ok();
|
||||
expect(client.id.length).to.be(40); // cid- + 32 hex chars (128 bits) + 4 hyphens
|
||||
expect(client.clientSecret.length).to.be(256); // 32 hex chars (8 * 256 bits)
|
||||
expect(data.Config.Env).to.contain('CLOUDRON_OAUTH_CLIENT_ID=' + client.id);
|
||||
expect(data.Config.Env).to.contain('CLOUDRON_OAUTH_CLIENT_SECRET=' + client.clientSecret);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('installation - app can populate addons', function (done) {
|
||||
superagent.get(`http://localhost:${appEntry.httpPort}/populate_addons`).end(function (error, res) {
|
||||
expect(!error).to.be.ok();
|
||||
|
||||
@@ -1,537 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* global it:false */
|
||||
/* global describe:false */
|
||||
/* global before:false */
|
||||
/* global after:false */
|
||||
|
||||
var accesscontrol = require('../../accesscontrol.js'),
|
||||
async = require('async'),
|
||||
constants = require('../../constants.js'),
|
||||
clients = require('../../clients.js'),
|
||||
database = require('../../database.js'),
|
||||
expect = require('expect.js'),
|
||||
uuid = require('uuid'),
|
||||
hat = require('../../hat.js'),
|
||||
superagent = require('superagent'),
|
||||
server = require('../../server.js');
|
||||
|
||||
var SERVER_URL = 'http://localhost:' + constants.PORT;
|
||||
|
||||
var USERNAME = 'superadmin', PASSWORD = 'Foobar?1337', EMAIL ='silly@me.com';
|
||||
var token = null;
|
||||
|
||||
function setup(done) {
|
||||
async.series([
|
||||
server.start,
|
||||
database._clear,
|
||||
|
||||
function (callback) {
|
||||
superagent.post(SERVER_URL + '/api/v1/cloudron/activate')
|
||||
.query({ setupToken: 'somesetuptoken' })
|
||||
.send({ username: USERNAME, password: PASSWORD, email: EMAIL })
|
||||
.end(function (error, result) {
|
||||
expect(result).to.be.ok();
|
||||
expect(result.statusCode).to.equal(201);
|
||||
|
||||
// stash token for further use
|
||||
token = result.body.token;
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
}
|
||||
|
||||
function cleanup(done) {
|
||||
database._clear(function (error) {
|
||||
expect(error).to.not.be.ok();
|
||||
|
||||
server.stop(done);
|
||||
});
|
||||
}
|
||||
|
||||
describe('OAuth Clients API', function () {
|
||||
describe('add', function () {
|
||||
before(setup),
|
||||
after(cleanup);
|
||||
|
||||
it('fails without token', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.send({ appId: 'someApp', redirectURI: 'http://foobar.com', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails without appId', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ redirectURI: 'http://foobar.com', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails with empty appId', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: '', redirectURI: 'http://foobar.com', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails without scope', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: 'someApp', redirectURI: 'http://foobar.com' })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails with empty scope', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: 'someApp', redirectURI: 'http://foobar.com', scope: '' })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails without redirectURI', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: 'someApp', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails with empty redirectURI', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: 'someApp', redirectURI: '', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails with malformed redirectURI', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: 'someApp', redirectURI: 'foobar', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails with invalid name', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: '$"$%^45asdfasdfadf.adf.', redirectURI: 'http://foobar.com', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds with dash', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: 'fo-1234-bar', redirectURI: 'http://foobar.com', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(201);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: 'someApp', redirectURI: 'http://foobar.com', scope: accesscontrol.SCOPE_PROFILE })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(201);
|
||||
expect(result.body.id).to.be.a('string');
|
||||
expect(result.body.appId).to.be.a('string');
|
||||
expect(result.body.redirectURI).to.be.a('string');
|
||||
expect(result.body.clientSecret).to.be.a('string');
|
||||
expect(result.body.scope).to.be.a('string');
|
||||
expect(result.body.type).to.equal(clients.TYPE_EXTERNAL);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', function () {
|
||||
var CLIENT_0 = {
|
||||
id: '',
|
||||
appId: 'someAppId-0',
|
||||
redirectURI: 'http://some.callback0',
|
||||
scope: accesscontrol.SCOPE_PROFILE
|
||||
};
|
||||
|
||||
before(function (done) {
|
||||
async.series([
|
||||
setup,
|
||||
|
||||
function (callback) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: CLIENT_0.appId, redirectURI: CLIENT_0.redirectURI, scope: CLIENT_0.scope })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(201);
|
||||
|
||||
CLIENT_0 = result.body;
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
|
||||
after(cleanup);
|
||||
|
||||
it('fails without token', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/' + CLIENT_0.id)
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('fails with unknown id', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/' + CLIENT_0.id.toUpperCase())
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/' + CLIENT_0.id)
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
expect(result.body).to.eql(CLIENT_0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('del', function () {
|
||||
var CLIENT_0 = {
|
||||
id: '',
|
||||
appId: 'someAppId-0',
|
||||
redirectURI: 'http://some.callback0',
|
||||
scope: accesscontrol.SCOPE_PROFILE
|
||||
};
|
||||
|
||||
var CLIENT_1 = {
|
||||
id: '',
|
||||
appId: 'someAppId-1',
|
||||
redirectURI: 'http://some.callback1',
|
||||
scope: accesscontrol.SCOPE_PROFILE,
|
||||
type: clients.TYPE_OAUTH
|
||||
};
|
||||
|
||||
before(function (done) {
|
||||
async.series([
|
||||
setup,
|
||||
|
||||
function (callback) {
|
||||
superagent.post(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.send({ appId: CLIENT_0.appId, redirectURI: CLIENT_0.redirectURI, scope: CLIENT_0.scope })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(201);
|
||||
|
||||
CLIENT_0 = result.body;
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
|
||||
after(cleanup);
|
||||
|
||||
it('fails without token', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/' + CLIENT_0.id)
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('fails with unknown id', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/' + CLIENT_0.id.toUpperCase())
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/' + CLIENT_0.id)
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(204);
|
||||
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/' + CLIENT_0.id)
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(404);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('fails for cid-webadmin', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/cid-webadmin')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(405);
|
||||
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/cid-webadmin')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('fails for addon auth client', function (done) {
|
||||
clients.add(CLIENT_1.appId, CLIENT_1.type, CLIENT_1.redirectURI, CLIENT_1.scope, function (error, result) {
|
||||
expect(error).to.equal(null);
|
||||
|
||||
CLIENT_1.id = result.id;
|
||||
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/' + CLIENT_1.id)
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(405);
|
||||
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/' + CLIENT_1.id)
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Clients', function () {
|
||||
var USER_0 = {
|
||||
userId: uuid.v4(),
|
||||
username: 'someusername',
|
||||
password: 'Strong#$%2345',
|
||||
email: 'some@email.com',
|
||||
admin: true,
|
||||
salt: 'somesalt',
|
||||
createdAt: (new Date()).toISOString(),
|
||||
modifiedAt: (new Date()).toISOString(),
|
||||
resetToken: hat(256)
|
||||
};
|
||||
|
||||
function setup2(done) {
|
||||
async.series([
|
||||
setup,
|
||||
|
||||
function (callback) {
|
||||
superagent.get(SERVER_URL + '/api/v1/profile')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result).to.be.ok();
|
||||
expect(result.statusCode).to.eql(200);
|
||||
|
||||
USER_0.id = result.body.id;
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
}
|
||||
|
||||
describe('get', function () {
|
||||
before(setup2);
|
||||
after(cleanup);
|
||||
|
||||
it('fails due to missing token', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients')
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to empty token', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: '' })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to wrong token', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token.toUpperCase() })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
|
||||
expect(result.body.clients.length).to.eql(3);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get tokens by client', function () {
|
||||
before(setup2);
|
||||
after(cleanup);
|
||||
|
||||
it('fails due to missing token', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to empty token', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.query({ access_token: '' })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to wrong token', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.query({ access_token: token.toUpperCase() })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to unkown client', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/CID-WEBADMIN/tokens')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
|
||||
expect(result.body.tokens.length).to.eql(1);
|
||||
expect(result.body.tokens[0].identifier).to.eql(USER_0.id);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete tokens by client', function () {
|
||||
before(setup2);
|
||||
after(cleanup);
|
||||
|
||||
it('fails due to missing token', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to empty token', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.query({ access_token: '' })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to wrong token', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.query({ access_token: token.toUpperCase() })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails due to unkown client', function (done) {
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/CID-WEBADMIN/tokens')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
|
||||
expect(result.body.tokens.length).to.eql(1);
|
||||
expect(result.body.tokens[0].identifier).to.eql(USER_0.id);
|
||||
|
||||
superagent.del(SERVER_URL + '/api/v1/clients/cid-webadmin/tokens')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(204);
|
||||
|
||||
// further calls with this token should not work
|
||||
superagent.get(SERVER_URL + '/api/v1/profile')
|
||||
.query({ access_token: token })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+1
-12
@@ -176,17 +176,6 @@ function initializeExpressSync() {
|
||||
router.post('/api/v1/groups/:groupId', token, authorizeAdmin, routes.groups.update);
|
||||
router.del ('/api/v1/groups/:groupId', token, authorizeAdmin, routes.groups.remove);
|
||||
|
||||
// client/token routes
|
||||
router.get ('/api/v1/clients', token, authorizeAdmin, routes.clients.getAll);
|
||||
router.post('/api/v1/clients', token, authorizeAdmin, routes.clients.add);
|
||||
router.get ('/api/v1/clients/:clientId', token, authorizeAdmin, routes.clients.get);
|
||||
router.post('/api/v1/clients/:clientId', token, authorizeAdmin, routes.clients.add);
|
||||
router.del ('/api/v1/clients/:clientId', token, authorizeAdmin, routes.clients.del);
|
||||
router.get ('/api/v1/clients/:clientId/tokens', token, authorizeAdmin, routes.clients.getTokens);
|
||||
router.post('/api/v1/clients/:clientId/tokens', token, authorizeAdmin, routes.clients.addToken);
|
||||
router.del ('/api/v1/clients/:clientId/tokens', token, authorizeAdmin, routes.clients.delTokens);
|
||||
router.del ('/api/v1/clients/:clientId/tokens/:tokenId', token, authorizeAdmin, routes.clients.delToken);
|
||||
|
||||
// appstore and subscription routes
|
||||
router.post('/api/v1/appstore/register_cloudron', token, authorizeAdmin, routes.appstore.registerCloudron);
|
||||
router.get ('/api/v1/appstore/subscription', token, authorizeAdmin, routes.appstore.getSubscription);
|
||||
@@ -231,7 +220,7 @@ function initializeExpressSync() {
|
||||
router.get ('/api/v1/apps/:id/logs', token, authorizeAdmin, routes.apps.getLogs);
|
||||
router.get ('/api/v1/apps/:id/exec', token, authorizeAdmin, routes.apps.exec);
|
||||
// websocket cannot do bearer authentication
|
||||
router.get ('/api/v1/apps/:id/execws', routes.accesscontrol.websocketAuth.bind(null, ROLE_ADMIN), routes.apps.execWebSocket);
|
||||
router.get ('/api/v1/apps/:id/execws', routes.accesscontrol.websocketAuth.bind(null, accesscontrol.ROLE_ADMIN), routes.apps.execWebSocket);
|
||||
router.post('/api/v1/apps/:id/clone', token, authorizeAdmin, routes.apps.cloneApp);
|
||||
router.get ('/api/v1/apps/:id/download', token, authorizeAdmin, routes.apps.downloadFile);
|
||||
router.post('/api/v1/apps/:id/upload', token, authorizeAdmin, multipart, routes.apps.uploadFile);
|
||||
|
||||
@@ -10,71 +10,11 @@ var accesscontrol = require('../accesscontrol.js'),
|
||||
expect = require('expect.js');
|
||||
|
||||
describe('access control', function () {
|
||||
describe('canonicalScopeString', function () {
|
||||
it('only * scope', function () {
|
||||
expect(accesscontrol.canonicalScopeString('*')).to.be(accesscontrol.VALID_SCOPES.join(','));
|
||||
});
|
||||
|
||||
it('identity for non-*', function () {
|
||||
expect(accesscontrol.canonicalScopeString('foo,bar')).to.be('bar,foo'); // becomes sorted
|
||||
});
|
||||
describe('verifyToken', function () {
|
||||
// FIXME
|
||||
});
|
||||
|
||||
describe('intersectScopes', function () { // args: allowed, wanted
|
||||
it('both are same', function () {
|
||||
expect(accesscontrol.intersectScopes([ 'apps', 'clients' ], [ 'apps', 'clients' ])).to.eql([ 'apps', 'clients' ]);
|
||||
});
|
||||
|
||||
it('some are different', function () {
|
||||
expect(accesscontrol.intersectScopes([ 'apps' ], [ 'apps', 'clients' ])).to.eql(['apps']);
|
||||
expect(accesscontrol.intersectScopes([ 'clients', 'domains', 'mail' ], [ 'mail' ])).to.eql(['mail']);
|
||||
});
|
||||
|
||||
it('everything is different', function () {
|
||||
expect(accesscontrol.intersectScopes(['cloudron', 'domains' ], ['apps','clients'])).to.eql([]);
|
||||
});
|
||||
|
||||
it('subscopes', function () {
|
||||
expect(accesscontrol.intersectScopes(['apps:read' ], ['apps'])).to.eql(['apps:read']);
|
||||
expect(accesscontrol.intersectScopes(['apps:read','domains','profile'], ['apps','domains:manage','profile'])).to.eql(['apps:read','domains:manage','profile']);
|
||||
expect(accesscontrol.intersectScopes(['apps:read','domains','profile'], ['apps','apps:read'])).to.eql(['apps:read']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateScopeString', function () {
|
||||
it('allows valid scopes', function () {
|
||||
expect(accesscontrol.validateScopeString('apps')).to.be(null);
|
||||
expect(accesscontrol.validateScopeString('apps,mail')).to.be(null);
|
||||
expect(accesscontrol.validateScopeString('apps:read,mail')).to.be(null);
|
||||
expect(accesscontrol.validateScopeString('apps,mail:write')).to.be(null);
|
||||
});
|
||||
|
||||
it('disallows invalid scopes', function () {
|
||||
expect(accesscontrol.validateScopeString('apps, mail')).to.be.an(Error);
|
||||
expect(accesscontrol.validateScopeString('random')).to.be.an(Error);
|
||||
expect(accesscontrol.validateScopeString('')).to.be.an(Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasScopes', function () {
|
||||
it('succeeds if it contains the scope', function () {
|
||||
expect(accesscontrol.hasScopes([ 'apps' ], [ 'apps' ])).to.be(null);
|
||||
expect(accesscontrol.hasScopes([ 'apps', 'mail' ], [ 'mail' ])).to.be(null);
|
||||
expect(accesscontrol.hasScopes([ 'clients', '*', 'apps', 'mail' ], [ 'mail' ])).to.be(null);
|
||||
|
||||
// subscope
|
||||
expect(accesscontrol.hasScopes([ 'apps' ], [ 'apps:read' ])).to.be(null);
|
||||
expect(accesscontrol.hasScopes([ 'apps:read' ], [ 'apps:read' ])).to.be(null);
|
||||
expect(accesscontrol.hasScopes([ 'apps' , 'mail' ], [ 'apps:*' ])).to.be(null);
|
||||
expect(accesscontrol.hasScopes([ '*' ], [ 'apps:read' ])).to.be(null);
|
||||
});
|
||||
|
||||
it('fails if it does not contain the scope', function () {
|
||||
expect(accesscontrol.hasScopes([ 'apps' ], [ 'mail' ])).to.be.an(Error);
|
||||
expect(accesscontrol.hasScopes([ 'apps', 'mail' ], [ 'clients' ])).to.be.an(Error);
|
||||
|
||||
// subscope
|
||||
expect(accesscontrol.hasScopes([ 'apps:write' ], [ 'apps:read' ])).to.be.an(Error);
|
||||
});
|
||||
describe('hasRole', function () {
|
||||
// FIXME
|
||||
});
|
||||
});
|
||||
|
||||
+3
-113
@@ -10,7 +10,6 @@ var appdb = require('../appdb.js'),
|
||||
async = require('async'),
|
||||
backupdb = require('../backupdb.js'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
clientdb = require('../clientdb.js'),
|
||||
database = require('../database'),
|
||||
domaindb = require('../domaindb'),
|
||||
eventlogdb = require('../eventlogdb.js'),
|
||||
@@ -723,7 +722,7 @@ describe('database', function () {
|
||||
identifier: '0',
|
||||
clientId: 'clientid-0',
|
||||
expires: Date.now() + 60 * 60000,
|
||||
scope: 'clients'
|
||||
scope: ''
|
||||
};
|
||||
var TOKEN_1 = {
|
||||
id: 'tid-1',
|
||||
@@ -732,7 +731,7 @@ describe('database', function () {
|
||||
identifier: '1',
|
||||
clientId: 'clientid-1',
|
||||
expires: Number.MAX_SAFE_INTEGER,
|
||||
scope: 'settings'
|
||||
scope: ''
|
||||
};
|
||||
var TOKEN_2 = {
|
||||
id: 'tid-2',
|
||||
@@ -741,7 +740,7 @@ describe('database', function () {
|
||||
identifier: '2',
|
||||
clientId: 'clientid-2',
|
||||
expires: Date.now(),
|
||||
scope: 'apps'
|
||||
scope: ''
|
||||
};
|
||||
|
||||
it('add succeeds', function (done) {
|
||||
@@ -1318,115 +1317,6 @@ describe('database', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('client', function () {
|
||||
var CLIENT_0 = {
|
||||
id: 'cid-0',
|
||||
appId: 'someappid_0',
|
||||
type: 'typeisastring',
|
||||
clientSecret: 'secret-0',
|
||||
redirectURI: 'http://foo.bar',
|
||||
scope: '*'
|
||||
|
||||
};
|
||||
var CLIENT_1 = {
|
||||
id: 'cid-1',
|
||||
appId: 'someappid_1',
|
||||
type: 'typeisastring',
|
||||
clientSecret: 'secret-',
|
||||
redirectURI: 'http://foo.bar',
|
||||
scope: '*'
|
||||
};
|
||||
|
||||
it('add succeeds', function (done) {
|
||||
clientdb.add(CLIENT_0.id, CLIENT_0.appId, CLIENT_0.type, CLIENT_0.clientSecret, CLIENT_0.redirectURI, CLIENT_0.scope, function (error) {
|
||||
expect(error).to.be(null);
|
||||
|
||||
clientdb.add(CLIENT_1.id, CLIENT_1.appId, CLIENT_0.type, CLIENT_1.clientSecret, CLIENT_1.redirectURI, CLIENT_1.scope, function (error) {
|
||||
expect(error).to.be(null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('add same client id fails', function (done) {
|
||||
clientdb.add(CLIENT_0.id, CLIENT_0.appId, CLIENT_0.type, CLIENT_0.clientSecret, CLIENT_0.redirectURI, CLIENT_0.scope, function (error) {
|
||||
expect(error).to.be.a(BoxError);
|
||||
expect(error.reason).to.equal(BoxError.ALREADY_EXISTS);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('get succeeds', function (done) {
|
||||
clientdb.get(CLIENT_0.id, function (error, result) {
|
||||
expect(error).to.be(null);
|
||||
expect(result).to.eql(CLIENT_0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('getByAppId succeeds', function (done) {
|
||||
clientdb.getByAppId(CLIENT_0.appId, function (error, result) {
|
||||
expect(error).to.be(null);
|
||||
expect(result).to.eql(CLIENT_0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('getByAppIdAndType succeeds', function (done) {
|
||||
clientdb.getByAppIdAndType(CLIENT_0.appId, CLIENT_0.type, function (error, result) {
|
||||
expect(error).to.be(null);
|
||||
expect(result).to.eql(CLIENT_0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('getByAppId fails for unknown client id', function (done) {
|
||||
clientdb.getByAppId(CLIENT_0.appId + CLIENT_0.appId, function (error, result) {
|
||||
expect(error).to.be.a(BoxError);
|
||||
expect(error.reason).to.equal(BoxError.NOT_FOUND);
|
||||
expect(result).to.not.be.ok();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('getAll succeeds', function (done) {
|
||||
clientdb.getAll(function (error, result) {
|
||||
expect(error).to.be(null);
|
||||
expect(result).to.be.an(Array);
|
||||
expect(result.length).to.equal(5); // three built-in clients
|
||||
expect(result[3]).to.eql(CLIENT_0);
|
||||
expect(result[4]).to.eql(CLIENT_1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('delByAppIdAndType succeeds', function (done) {
|
||||
clientdb.delByAppIdAndType(CLIENT_1.appId, CLIENT_1.type, function (error) {
|
||||
expect(error).to.be(null);
|
||||
|
||||
clientdb.getByAppIdAndType(CLIENT_1.appId, CLIENT_1.type, function (error, result) {
|
||||
expect(error).to.be.a(BoxError);
|
||||
expect(error.reason).to.equal(BoxError.NOT_FOUND);
|
||||
expect(result).to.not.be.ok();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('delByAppId succeeds', function (done) {
|
||||
clientdb.delByAppId(CLIENT_0.appId, function (error) {
|
||||
expect(error).to.be(null);
|
||||
|
||||
clientdb.getByAppId(CLIENT_0.appId, function (error, result) {
|
||||
expect(error).to.be.a(BoxError);
|
||||
expect(error.reason).to.equal(BoxError.NOT_FOUND);
|
||||
expect(result).to.not.be.ok();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('settings', function () {
|
||||
it('can set value', function (done) {
|
||||
settingsdb.set('somekey', 'somevalue', function (error) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
addTokenByUserId: addTokenByUserId,
|
||||
|
||||
// token client ids. we categorize them so we can have different restrictions based on the client
|
||||
ID_WEBADMIN: 'cid-webadmin', // dashboard oauth
|
||||
ID_SDK: 'cid-sdk', // created by user via dashboard
|
||||
ID_CLI: 'cid-cli' // created via cli tool
|
||||
};
|
||||
|
||||
let assert = require('assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
hat = require('./hat.js'),
|
||||
uuid = require('uuid'),
|
||||
tokendb = require('./tokendb.js');
|
||||
|
||||
function validateTokenName(name) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
|
||||
if (name.length > 64) return new BoxError(BoxError.BAD_FIELD, 'name too long', { field: 'name' });
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function addTokenByUserId(clientId, userId, expiresAt, options, callback) {
|
||||
assert.strictEqual(typeof clientId, 'string');
|
||||
assert.strictEqual(typeof userId, 'string');
|
||||
assert.strictEqual(typeof expiresAt, 'number');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
const name = options.name || '';
|
||||
let error = validateTokenName(name);
|
||||
if (error) return callback(error);
|
||||
|
||||
const token = {
|
||||
id: 'tid-' + uuid.v4(),
|
||||
accessToken: hat(8 * 32),
|
||||
identifier: userId,
|
||||
clientId: clientId,
|
||||
expires: expiresAt,
|
||||
scope: 'unused',
|
||||
name: name
|
||||
};
|
||||
|
||||
tokendb.add(token, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null, {
|
||||
accessToken: token.accessToken,
|
||||
tokenScopes: 'unused',
|
||||
identifier: userId,
|
||||
clientId: clientId,
|
||||
expires: expiresAt
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user