feature: remove profile and remove key

This commit is contained in:
Esteban Ordano 2014-11-12 23:52:45 -03:00
parent 02bc5b4580
commit 45e6241e34
3 changed files with 180 additions and 31 deletions

View File

@ -63,6 +63,9 @@ module.exports = function(app) {
app.post(apiPrefix + '/email/register', emailPlugin.oldSave);
app.get(apiPrefix + '/email/retrieve/:email', emailPlugin.oldRetrieve);
app.post(apiPrefix + '/email/delete/profile', emailPlugin.eraseProfile);
app.post(apiPrefix + '/email/delete/item/:key', emailPlugin.erase);
}
// Address routes

View File

@ -315,6 +315,48 @@
});
};
emailPlugin.deleteByEmailAndKey = function deleteByEmailAndKey(email, key, callback) {
emailPlugin.db.del(valueKey(email, key), function(error) {
if (error) {
if (error.notFound) {
return callback(emailPlugin.errors.NOT_FOUND);
} else {
logger.error(error);
return callback(emailPlugin.errors.INTERNAL_ERROR);
}
}
return callback();
});
};
emailPlugin.deleteWholeProfile = function deleteWholeProfile(email, callback) {
var dismissNotFound = function(callback) {
return function(error, result) {
if (error && error.notFound) {
return callback();
}
return callback(error, result);
};
};
async.parallel([
function(callback) {
emailPlugin.db.del(emailToPassphrase(email), dismissNotFound(callback));
},
function(callback) {
emailPlugin.db.del(pendingKey(email), dismissNotFound(callback));
},
function(callback) {
emailPlugin.db.del(validatedKey(email), dismissNotFound(callback));
}
], function(err) {
if (err) {
logger.error(err);
return callback(emailPlugin.errors.INTERNAL_ERROR);
}
return callback();
});
};
/**
* Store a record in the database. The underlying database is merely a levelup instance (a key
* value store) that uses the email concatenated with the secret as a key to store the record.
@ -424,7 +466,6 @@
});
};
emailPlugin.getCredentialsFromRequest = function(request) {
var auth = request.header('authorization');
if (!auth) {
@ -444,51 +485,103 @@
};
};
emailPlugin.addValidationHeader = function(response, email, callback) {
emailPlugin.db.get(validatedKey(email), function(err, value) {
if (err && !err.notFound)
if (err && !err.notFound) {
return callback(err);
}
if (value)
if (value) {
return callback();
}
response.set('X-Email-Needs-Validation', 'true');
return callback(null, value || false);
return callback(null, value);
});
};
function authorizedRequest(withKey, callback) {
return function(request, response) {
var credentialsResult = emailPlugin.getCredentialsFromRequest(request);
if (_.contains(emailPlugin.errors, credentialsResult)) {
return emailPlugin.returnError(credentialsResult, response);
}
var email = credentialsResult.email;
var passphrase = credentialsResult.passphrase;
var key;
if (withKey) {
key = request.param('key');
}
if (!passphrase || !email || (withKey && !key)) {
return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response);
}
return callback(email, passphrase, key, request, response);
};
}
/**
* Retrieve a record from the database
*/
emailPlugin.retrieve = function(request, response) {
var credentialsResult = emailPlugin.getCredentialsFromRequest(request);
if (_.contains(emailPlugin.errors, credentialsResult)) {
return emailPlugin.returnError(credentialsResult);
}
var email = credentialsResult.email;
var passphrase = credentialsResult.passphrase;
var key = request.param('key');
if (!passphrase || !email || !key) {
return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response);
}
emailPlugin.retrieveDataByEmailAndPassphrase(email, key, passphrase, function(err, value) {
if (err)
return emailPlugin.returnError(err, response);
emailPlugin.addValidationHeader(response, email, function(err) {
if (err)
emailPlugin.retrieve = authorizedRequest(true,
function(email, passphrase, key, request, response) {
emailPlugin.retrieveDataByEmailAndPassphrase(email, key, passphrase, function(err, value) {
if (err) {
return emailPlugin.returnError(err, response);
response.send(value).end();
}
emailPlugin.addValidationHeader(response, email, function(err) {
if (err) {
return emailPlugin.returnError(err, response);
}
response.send(value).end();
});
});
});
};
}
);
/**
* Remove a record from the database
*/
emailPlugin.erase = authorizedRequest(true,
function(email, passphrase, key, request, response) {
emailPlugin.checkPassphrase(email, passphrase, function(err, matches) {
if (err || !matches) {
return emailPlugin.returnError(emailPlugin.errors.INVALID_CODE, response);
}
emailPlugin.deleteByEmailAndKey(email, key, function(err, value) {
if (err) {
return emailPlugin.returnError(err, response);
} else {
return response.json({success: true}).end();
};
});
});
}
);
/**
* Remove a whole profile from the database
*
* @TODO: This looks very similar to the method above
*/
emailPlugin.eraseProfile = authorizedRequest(false,
function(email, passphrase, unused_key, request, response) {
emailPlugin.checkPassphrase(email, passphrase, function(err, matches) {
if (err || !matches) {
return emailPlugin.returnError(emailPlugin.errors.INVALID_CODE, response);
}
emailPlugin.deleteWholeProfile(email, function(err, value) {
if (err) {
return emailPlugin.returnError(err, response);
} else {
return response.json({success: true}).end();
};
});
});
}
);
/**
* Marks an email as validated

View File

@ -377,6 +377,59 @@ describe('emailstore test', function() {
});
});
describe('removing items', function() {
var fakeEmail = 'fake@email.com';
var fakeKey = 'nameForData';
beforeEach(function() {
leveldb_stub.del = sinon.stub();
});
it('deletes a stored element (key)', function(done) {
leveldb_stub.del.onFirstCall().callsArg(1);
plugin.deleteByEmailAndKey(fakeEmail, fakeKey, function(err) {
expect(err).to.be.undefined;
done();
});
});
it('returns NOT FOUND if trying to delete a stored element by key', function(done) {
leveldb_stub.del.onFirstCall().callsArgWith(1, {notFound: true});
plugin.deleteByEmailAndKey(fakeEmail, fakeKey, function(err) {
err.should.equal(plugin.errors.NOT_FOUND);
done();
});
});
it('returns INTERNAL_ERROR if an unexpected error ocurrs', function(done) {
leveldb_stub.del.onFirstCall().callsArgWith(1, {unexpected: true});
plugin.deleteByEmailAndKey(fakeEmail, fakeKey, function(err) {
err.should.equal(plugin.errors.INTERNAL_ERROR);
done();
});
});
it('can delete a whole profile (validation data and passphrase)', function(done) {
leveldb_stub.del.callsArg(1);
plugin.deleteWholeProfile(fakeEmail, function(err) {
expect(err).to.be.undefined;
leveldb_stub.del.callCount.should.equal(3);
done();
});
});
it('dismisses not found errors', function(done) {
leveldb_stub.del.callsArg(1);
leveldb_stub.del.onSecondCall().callsArgWith(1, {notFound: true});
plugin.deleteWholeProfile(fakeEmail, function(err) {
expect(err).to.be.undefined;
done();
});
});
it('returns internal error if something goes awry', function(done) {
leveldb_stub.del.callsArg(1);
leveldb_stub.del.onSecondCall().callsArgWith(1, {unexpected: true});
plugin.deleteWholeProfile(fakeEmail, function(err) {
err.should.equal(plugin.errors.INTERNAL_ERROR);
done();
});
});
});
describe('when retrieving data', function() {
it('should validate the secret and return the data', function() {