Move ClientsError to BoxError

This commit is contained in:
Girish Ramakrishnan
2019-10-22 21:16:00 -07:00
parent 11d80cec7d
commit 2df642000d
6 changed files with 62 additions and 82 deletions
+3 -3
View File
@@ -27,6 +27,7 @@ exports = module.exports = {
};
var assert = require('assert'),
BoxError = require('./boxerror.js'),
DatabaseError = require('./databaseerror.js'),
debug = require('debug')('box:accesscontrol'),
tokendb = require('./tokendb.js'),
@@ -78,13 +79,12 @@ function intersectScopes(allowedScopes, wantedScopes) {
function validateScopeString(scope) {
assert.strictEqual(typeof scope, 'string');
if (scope === '') return new Error('Empty scope not allowed');
if (scope === '') return new BoxError(BoxError.BAD_FIELD, 'Empty scope not allowed', { field: 'scope' });
// NOTE: this function intentionally does not allow '*'. This is only allowed in the db to allow
// us not write a migration script every time we add a new scope
var allValid = scope.split(',').every(function (s) { return exports.VALID_SCOPES.indexOf(s.split(':')[0]) !== -1; });
if (!allValid) return new Error('Invalid scope. Available scopes are ' + exports.VALID_SCOPES.join(', '));
if (!allValid) return new BoxError(BoxError.BAD_FIELD, 'Invalid scope. Available scopes are ' + exports.VALID_SCOPES.join(', '), { field: 'scope' });
return null;
}
+2 -3
View File
@@ -39,7 +39,6 @@ var accesscontrol = require('./accesscontrol.js'),
BoxError = require('./boxerror.js'),
clients = require('./clients.js'),
constants = require('./constants.js'),
ClientsError = clients.ClientsError,
crypto = require('crypto'),
DatabaseError = require('./databaseerror.js'),
debug = require('debug')('box:addons'),
@@ -816,7 +815,7 @@ function setupOauth(app, options, callback) {
var scope = accesscontrol.SCOPE_PROFILE;
clients.delByAppIdAndType(appId, clients.TYPE_OAUTH, function (error) { // remove existing creds
if (error && error.reason !== ClientsError.NOT_FOUND) return callback(error);
if (error && error.reason !== BoxError.NOT_FOUND) return callback(error);
clients.add(appId, clients.TYPE_OAUTH, redirectURI, scope, function (error, result) {
if (error) return callback(error);
@@ -844,7 +843,7 @@ function teardownOauth(app, options, callback) {
debugApp(app, 'teardownOauth');
clients.delByAppIdAndType(app.id, clients.TYPE_OAUTH, function (error) {
if (error && error.reason !== ClientsError.NOT_FOUND) debug(error);
if (error && error.reason !== BoxError.NOT_FOUND) debug(error);
appdb.unsetAddonConfig(app.id, 'oauth', callback);
});
+24 -50
View File
@@ -1,8 +1,6 @@
'use strict';
exports = module.exports = {
ClientsError: ClientsError,
add: add,
get: get,
del: del,
@@ -30,6 +28,7 @@ exports = module.exports = {
var apps = require('./apps.js'),
assert = require('assert'),
async = require('async'),
BoxError = require('./boxerror.js'),
clientdb = require('./clientdb.js'),
constants = require('./constants.js'),
DatabaseError = require('./databaseerror.js'),
@@ -40,44 +39,16 @@ var apps = require('./apps.js'),
tokendb = require('./tokendb.js'),
users = require('./users.js'),
UsersError = users.UsersError,
util = require('util'),
uuid = require('uuid'),
_ = require('underscore');
function ClientsError(reason, errorOrMessage) {
assert.strictEqual(typeof reason, 'string');
assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined');
Error.call(this);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.reason = reason;
if (typeof errorOrMessage === 'undefined') {
this.message = reason;
} else if (typeof errorOrMessage === 'string') {
this.message = errorOrMessage;
} else {
this.message = 'Internal error';
this.nestedError = errorOrMessage;
}
}
util.inherits(ClientsError, Error);
ClientsError.INVALID_SCOPE = 'Invalid scope';
ClientsError.INVALID_CLIENT = 'Invalid client';
ClientsError.INVALID_TOKEN = 'Invalid token';
ClientsError.BAD_FIELD = 'Bad field';
ClientsError.NOT_FOUND = 'Not found';
ClientsError.INTERNAL_ERROR = 'Internal Error';
ClientsError.NOT_ALLOWED = 'Not allowed to remove this client';
function validateClientName(name) {
assert.strictEqual(typeof name, 'string');
if (name.length < 1) return new ClientsError(ClientsError.BAD_FIELD, 'Name must be atleast 1 character');
if (name.length > 128) return new ClientsError(ClientsError.BAD_FIELD, 'Name too long');
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 ClientsError(ClientsError.BAD_FIELD, 'Username can only contain alphanumerals and dash');
if (/[^a-zA-Z0-9-]/.test(name)) return new BoxError(BoxError.BAD_FIELD, 'name can only contain alphanumerals and dash', { field: 'name' });
return null;
}
@@ -85,7 +56,7 @@ function validateClientName(name) {
function validateTokenName(name) {
assert.strictEqual(typeof name, 'string');
if (name.length > 64) return new ClientsError(ClientsError.BAD_FIELD, 'Name too long');
if (name.length > 64) return new BoxError(BoxError.BAD_FIELD, 'name too long', { field: 'name' });
return null;
}
@@ -98,7 +69,7 @@ function add(appId, type, redirectURI, scope, callback) {
assert.strictEqual(typeof callback, 'function');
var error = accesscontrol.validateScopeString(scope);
if (error) return callback(new ClientsError(ClientsError.INVALID_SCOPE, error.message));
if (error) return callback(error);
error = validateClientName(appId);
if (error) return callback(error);
@@ -127,8 +98,9 @@ function get(id, callback) {
assert.strictEqual(typeof callback, 'function');
clientdb.get(id, function (error, result) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new ClientsError(ClientsError.NOT_FOUND, 'No such client'));
if (error) return callback(error);
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such client'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
callback(null, result);
});
}
@@ -138,8 +110,9 @@ function del(id, callback) {
assert.strictEqual(typeof callback, 'function');
clientdb.del(id, function (error, result) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new ClientsError(ClientsError.NOT_FOUND, 'No such client'));
if (error) return callback(error);
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such client'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
callback(null, result);
});
}
@@ -149,7 +122,7 @@ function getAll(callback) {
clientdb.getAll(function (error, results) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(null, []);
if (error) return callback(error);
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
var tmp = [];
async.each(results, function (record, callback) {
@@ -190,8 +163,9 @@ function getByAppIdAndType(appId, type, callback) {
assert.strictEqual(typeof callback, 'function');
clientdb.getByAppIdAndType(appId, type, function (error, result) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new ClientsError(ClientsError.NOT_FOUND, 'No such client'));
if (error) return callback(error);
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such client'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
callback(null, result);
});
}
@@ -243,10 +217,10 @@ function delByAppIdAndType(appId, type, callback) {
if (error) return callback(error);
tokendb.delByClientId(result.id, function (error) {
if (error && error.reason !== DatabaseError.NOT_FOUND) return callback(new ClientsError(ClientsError.INTERNAL_ERROR, error));
if (error && error.reason !== DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
clientdb.delByAppIdAndType(appId, type, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new ClientsError(ClientsError.NOT_FOUND, 'No such client'));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such client'));
if (error) return callback(error);
callback(null);
@@ -270,11 +244,11 @@ function addTokenByUserId(clientId, userId, expiresAt, options, callback) {
if (error) return callback(error);
users.get(userId, function (error, user) {
if (error && error.reason === UsersError.NOT_FOUND) return callback(new ClientsError(ClientsError.NOT_FOUND, 'No such user'));
if (error) return callback(new ClientsError(ClientsError.INTERNAL_ERROR, error));
if (error && error.reason === UsersError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such user'));
if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error));
accesscontrol.scopesForUser(user, function (error, userScopes) {
if (error) return callback(new ClientsError(ClientsError.INTERNAL_ERROR, error));
if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error));
const scope = accesscontrol.canonicalScopeString(result.scope);
const authorizedScopes = accesscontrol.intersectScopes(userScopes, scope.split(','));
@@ -290,7 +264,7 @@ function addTokenByUserId(clientId, userId, expiresAt, options, callback) {
};
tokendb.add(token, function (error) {
if (error) return callback(new ClientsError(ClientsError.INTERNAL_ERROR, error));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
callback(null, {
accessToken: token.accessToken,
@@ -331,8 +305,8 @@ function delToken(clientId, tokenId, callback) {
if (error) return callback(error);
tokendb.del(tokenId, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new ClientsError(ClientsError.INVALID_TOKEN, 'Invalid token'));
if (error) return callback(new ClientsError(ClientsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'Invalid token'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
callback(null);
});
+3 -3
View File
@@ -12,9 +12,9 @@ var accesscontrol = require('../accesscontrol.js'),
assert = require('assert'),
BasicStrategy = require('passport-http').BasicStrategy,
BearerStrategy = require('passport-http-bearer').Strategy,
BoxError = require('../boxerror.js'),
clients = require('../clients.js'),
ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy,
ClientsError = clients.ClientsError,
HttpError = require('connect-lastmile').HttpError,
LocalStrategy = require('passport-local').Strategy,
passport = require('passport'),
@@ -62,7 +62,7 @@ function initialize(callback) {
// Used to authenticate a OAuth2 client which uses clientId and clientSecret in the Authorization header
passport.use(new BasicStrategy(function (clientId, clientSecret, callback) {
clients.get(clientId, function (error, client) {
if (error && error.reason === ClientsError.NOT_FOUND) return callback(null, false);
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false);
if (error) return callback(error);
if (client.clientSecret !== clientSecret) return callback(null, false);
callback(null, client);
@@ -72,7 +72,7 @@ function initialize(callback) {
// Used to authenticate a OAuth2 client which uses clientId and clientSecret in the request body (client_id, client_secret)
passport.use(new ClientPasswordStrategy(function (clientId, clientSecret, callback) {
clients.get(clientId, function(error, client) {
if (error && error.reason === ClientsError.NOT_FOUND) return callback(null, false);
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false);
if (error) { return callback(error); }
if (client.clientSecret !== clientSecret) { return callback(null, false); }
callback(null, client);
+28 -21
View File
@@ -12,13 +12,25 @@ exports = module.exports = {
};
var assert = require('assert'),
BoxError = require('../boxerror.js'),
clients = require('../clients.js'),
ClientsError = clients.ClientsError,
constants = require('../constants.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
validUrl = require('valid-url');
function toHttpError(error) {
switch (error.reason) {
case BoxError.NOT_FOUND:
return new HttpError(404, error);
case BoxError.BAD_FIELD:
return new HttpError(400, error);
case BoxError.INTERNAL_ERROR:
default:
return new HttpError(500, error);
}
}
function add(req, res, next) {
var data = req.body;
@@ -29,9 +41,8 @@ function add(req, res, next) {
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 && error.reason === ClientsError.INVALID_SCOPE) return next(new HttpError(400, error.message));
if (error && error.reason === ClientsError.BAD_FIELD) return next(new HttpError(400, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
next(new HttpSuccess(201, result));
});
}
@@ -40,8 +51,8 @@ function get(req, res, next) {
assert.strictEqual(typeof req.params.clientId, 'string');
clients.get(req.params.clientId, function (error, result) {
if (error && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(404, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
next(new HttpSuccess(200, result));
});
}
@@ -50,16 +61,14 @@ function del(req, res, next) {
assert.strictEqual(typeof req.params.clientId, 'string');
clients.get(req.params.clientId, function (error, result) {
if (error && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(404, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(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 && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(404, error.message));
if (error && error.reason === ClientsError.NOT_ALLOWED) return next(new HttpError(405, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
next(new HttpSuccess(204, result));
});
});
@@ -67,7 +76,8 @@ function del(req, res, next) {
function getAll(req, res, next) {
clients.getAll(function (error, result) {
if (error && error.reason !== ClientsError.NOT_FOUND) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
next(new HttpSuccess(200, { clients: result }));
});
}
@@ -83,8 +93,8 @@ function addToken(req, res, next) {
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 && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(404, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
next(new HttpSuccess(201, { token: result }));
});
}
@@ -94,8 +104,7 @@ function getTokens(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
clients.getTokensByUserId(req.params.clientId, req.user.id, function (error, result) {
if (error && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(404, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
result = result.map(clients.removeTokenPrivateFields);
@@ -108,8 +117,8 @@ function delTokens(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
clients.delTokensByUserId(req.params.clientId, req.user.id, function (error) {
if (error && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(404, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
next(new HttpSuccess(204));
});
}
@@ -120,9 +129,7 @@ function delToken(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
clients.delToken(req.params.clientId, req.params.tokenId, function (error) {
if (error && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(404, error.message));
if (error && error.reason === ClientsError.INVALID_TOKEN) return next(new HttpError(404, error.message));
if (error) return next(new HttpError(500, error));
if (error) return next(toHttpError(error));
next(new HttpSuccess(204));
});
+2 -2
View File
@@ -22,8 +22,8 @@ exports = module.exports = {
var apps = require('../apps.js'),
assert = require('assert'),
authcodedb = require('../authcodedb.js'),
BoxError = require('../boxerror.js'),
clients = require('../clients'),
ClientsError = clients.ClientsError,
constants = require('../constants.js'),
DatabaseError = require('../databaseerror.js'),
debug = require('debug')('box:routes/oauth2'),
@@ -463,7 +463,7 @@ function authorization() {
debug('authorization: client %s with callback to %s.', clientId, redirectURI);
clients.get(clientId, function (error, client) {
if (error && error.reason === ClientsError.NOT_FOUND) return callback(null, false);
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false);
if (error) return callback(error);
// ignore the origin passed into form the client, but use the one from the clientdb