Generate tokens and ids with cryptoUtils module.
Move object ID, token, and random string generation into their own module, cryptoUtils. Remove hat dependency, which was used to generate session and some other tokens, because it used non-cryptographic random number generator. Replace it with the cryptographically secure one. The result has the same format (32-character hex string, 128 bits of entropy). Remove randomstring dependency, as we already have this functionality. Add tests.
This commit is contained in:
@@ -2,13 +2,12 @@
|
||||
// that writes to the database.
|
||||
// This could be either a "create" or an "update".
|
||||
|
||||
var crypto = require('crypto');
|
||||
var deepcopy = require('deepcopy');
|
||||
var rack = require('hat').rack();
|
||||
|
||||
var Auth = require('./Auth');
|
||||
var cache = require('./cache');
|
||||
var Config = require('./Config');
|
||||
var cryptoUtils = require('./cryptoUtils');
|
||||
var passwordCrypto = require('./password');
|
||||
var facebook = require('./facebook');
|
||||
var Parse = require('parse/node');
|
||||
@@ -56,7 +55,7 @@ function RestWrite(config, auth, className, query, data, originalData) {
|
||||
this.data.updatedAt = this.updatedAt;
|
||||
if (!this.query) {
|
||||
this.data.createdAt = this.updatedAt;
|
||||
this.data.objectId = newStringId(10);
|
||||
this.data.objectId = cryptoUtils.newObjectId();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +251,7 @@ RestWrite.prototype.handleFacebookAuthData = function() {
|
||||
throw new Parse.Error(Parse.Error.ACCOUNT_ALREADY_LINKED,
|
||||
'this auth is already used');
|
||||
} else {
|
||||
this.data.username = rack();
|
||||
this.data.username = cryptoUtils.newToken();
|
||||
}
|
||||
|
||||
// This FB auth does not already exist, so transform it to a
|
||||
@@ -273,7 +272,7 @@ RestWrite.prototype.transformUser = function() {
|
||||
var promise = Promise.resolve();
|
||||
|
||||
if (!this.query) {
|
||||
var token = 'r:' + rack();
|
||||
var token = 'r:' + cryptoUtils.newToken();
|
||||
this.storage['token'] = token;
|
||||
promise = promise.then(() => {
|
||||
var expiresAt = new Date();
|
||||
@@ -319,7 +318,7 @@ RestWrite.prototype.transformUser = function() {
|
||||
// Check for username uniqueness
|
||||
if (!this.data.username) {
|
||||
if (!this.query) {
|
||||
this.data.username = newStringId(25);
|
||||
this.data.username = cryptoUtils.randomString(25);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -412,7 +411,7 @@ RestWrite.prototype.handleSession = function() {
|
||||
}
|
||||
|
||||
if (!this.query && !this.auth.isMaster) {
|
||||
var token = 'r:' + rack();
|
||||
var token = 'r:' + cryptoUtils.newToken();
|
||||
var expiresAt = new Date();
|
||||
expiresAt.setFullYear(expiresAt.getFullYear() + 1);
|
||||
var sessionData = {
|
||||
@@ -713,20 +712,4 @@ RestWrite.prototype.objectId = function() {
|
||||
return this.data.objectId || this.query.objectId;
|
||||
};
|
||||
|
||||
// Returns a unique string that's usable as an object or other id.
|
||||
function newStringId(size) {
|
||||
var chars = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
|
||||
'abcdefghijklmnopqrstuvwxyz' +
|
||||
'0123456789');
|
||||
var objectId = '';
|
||||
var bytes = crypto.randomBytes(size);
|
||||
for (var i = 0; i < bytes.length; ++i) {
|
||||
// Note: there is a slight modulo bias, because chars length
|
||||
// of 62 doesn't divide the number of all bytes (256) evenly.
|
||||
// It is acceptable for our purposes.
|
||||
objectId += chars[bytes.readUInt8(i) % chars.length];
|
||||
}
|
||||
return objectId;
|
||||
}
|
||||
|
||||
module.exports = RestWrite;
|
||||
|
||||
Reference in New Issue
Block a user