mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-23 02:41:50 +03:00
Added secret.create util to security package
- this utility existed twice in the ghost codebase: -f6fb823ce9/core/server/models/api-key.js (L24)
-f6fb823ce9/core/server/data/migrations/versions/4.0/22-solve-orphaned-webhooks.js (L7)
- We also potentially need it for a second migration use case - so moved it here, made it slightly more generic and also deprecated identifier.uid in favour of using this method as they do the same thing, but secret.create uses crypto properly
This commit is contained in:
parent
877fdc7bfe
commit
3a7613a46e
@ -17,5 +17,9 @@ module.exports = {
|
||||
|
||||
get password() {
|
||||
return require('./lib/password');
|
||||
},
|
||||
|
||||
get secret() {
|
||||
return require('./lib/secret');
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,5 @@
|
||||
let _private = {};
|
||||
|
||||
// @TODO: replace with crypto.randomBytes
|
||||
_private.getRandomInt = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
};
|
||||
@ -8,9 +7,9 @@ _private.getRandomInt = function (min, max) {
|
||||
/**
|
||||
* Return a unique identifier with the given `len`.
|
||||
*
|
||||
* @deprecated use secret.create() instead
|
||||
* @param {Number} maxLength
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
module.exports.uid = function uid(maxLength) {
|
||||
const buf = [];
|
||||
|
40
ghost/security/lib/secret.js
Normal file
40
ghost/security/lib/secret.js
Normal file
@ -0,0 +1,40 @@
|
||||
const crypto = require('crypto');
|
||||
|
||||
/*
|
||||
* Uses birthday problem estimation to calculate chance of collision
|
||||
* d = 16^26 // 26 char hex string
|
||||
* n = 10,000,000 // 10 million
|
||||
*
|
||||
* (-n x (n-1)) / 2d
|
||||
* 1 - e^
|
||||
*
|
||||
*
|
||||
* 17
|
||||
* ~= 4 x 10^
|
||||
*
|
||||
* ref: https://medium.freecodecamp.org/how-long-should-i-make-my-api-key-833ebf2dc26f
|
||||
* ref: https://en.wikipedia.org/wiki/Birthday_problem#Approximations
|
||||
*
|
||||
* 26 char hex string = 13 bytes (content api)
|
||||
* 64 char hex string JWT secret = 32 bytes (admin api / default)
|
||||
*
|
||||
* @param {String|Number} [typeOrLength=64]
|
||||
* @returns
|
||||
*/
|
||||
module.exports.create = (typeOrLength) => {
|
||||
let bytes;
|
||||
let length;
|
||||
|
||||
if (Number.isInteger(typeOrLength)) {
|
||||
bytes = Math.ceil(typeOrLength / 2);
|
||||
length = typeOrLength;
|
||||
} else if (typeOrLength === 'content') {
|
||||
bytes = 13;
|
||||
length = 26;
|
||||
} else {
|
||||
bytes = 32;
|
||||
length = 64;
|
||||
}
|
||||
|
||||
return crypto.randomBytes(bytes).toString('hex').slice(0, length);
|
||||
};
|
34
ghost/security/test/secret.test.js
Normal file
34
ghost/security/test/secret.test.js
Normal file
@ -0,0 +1,34 @@
|
||||
require('./utils');
|
||||
const security = require('../');
|
||||
|
||||
describe('Lib: Security - Secret', function () {
|
||||
it('generates a 13 byte secret if asked for a content secret', function () {
|
||||
let secret = security.secret.create('content');
|
||||
secret.should.be.a.String().with.lengthOf(13 * 2);
|
||||
secret.should.match(/[0-9][a-z]+/);
|
||||
});
|
||||
|
||||
it('generates a specific length secret if given a length', function () {
|
||||
let secret = security.secret.create(10);
|
||||
secret.should.be.a.String().with.lengthOf(10);
|
||||
secret.should.match(/[0-9][a-z]+/);
|
||||
});
|
||||
|
||||
it('generates a specific length secret if given a length even when odd', function () {
|
||||
let secret = security.secret.create(15);
|
||||
secret.should.be.a.String().with.lengthOf(15);
|
||||
secret.should.match(/[0-9][a-z]+/);
|
||||
});
|
||||
|
||||
it('generates a 32 byte secret if asked for an admin secret', function () {
|
||||
let secret = security.secret.create('admin');
|
||||
secret.should.be.a.String().with.lengthOf(32 * 2);
|
||||
secret.should.match(/[0-9][a-z]+/);
|
||||
});
|
||||
|
||||
it('generates a 32 byte secret by default', function () {
|
||||
let secret = security.secret.create();
|
||||
secret.should.be.a.String().with.lengthOf(32 * 2);
|
||||
secret.should.match(/[0-9][a-z]+/);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user