From 117d0bbb0f2887262a6a170b9503f230037daf98 Mon Sep 17 00:00:00 2001 From: ItzNotABug Date: Sat, 6 Jul 2024 17:58:34 +0530 Subject: [PATCH 1/3] update: signature check logic. --- utils/misc.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/utils/misc.js b/utils/misc.js index 483db7b..de4ee8e 100644 --- a/utils/misc.js +++ b/utils/misc.js @@ -326,12 +326,34 @@ export default class Miscellaneous { return false; } - const expectedSignature = crypto + /** + * Build signature with new logic for `Ghost:5.87.1` & above. + * @see https://github.com/TryGhost/Ghost/pull/20500 + */ + const expectedNewSignature = crypto + .createHmac('sha256', ghostConfigs.secret) + .update(`${payload}${timeStamp}`) + .digest('hex'); + + /** + * Build signature for versions below `Ghost:5.87.1`. + */ + const expectedOldSignature = crypto .createHmac('sha256', ghostConfigs.secret) .update(payload) .digest('hex'); - return signature === expectedSignature; + if (signature === expectedNewSignature) { + return true; + } else if (signature === expectedOldSignature) { + return true; + } else { + logError( + logTags.Express, + "The signature in the 'X-Ghost-Signature' header is not valid.", + ); + return false; + } } /** From 6fd64866166d5d2a3013cf1db3e09ada26b830ae Mon Sep 17 00:00:00 2001 From: ItzNotABug Date: Sat, 6 Jul 2024 17:59:21 +0530 Subject: [PATCH 2/3] misc: use dynamic year in newsletter. --- views/newsletter.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/newsletter.ejs b/views/newsletter.ejs index 81d8322..facaba6 100644 --- a/views/newsletter.ejs +++ b/views/newsletter.ejs @@ -1329,7 +1329,7 @@ <%= site.title %> © 2023 – <%= site.title %> © <%= new Date().getFullYear() %> – Unsubscribe From e8118fac94303c36d4b34c460bf047abf4bf0e74 Mon Sep 17 00:00:00 2001 From: ItzNotABug Date: Sat, 6 Jul 2024 18:24:13 +0530 Subject: [PATCH 3/3] update: address comments. --- utils/misc.js | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/utils/misc.js b/utils/misc.js index de4ee8e..79806a6 100644 --- a/utils/misc.js +++ b/utils/misc.js @@ -292,11 +292,11 @@ export default class Miscellaneous { */ static async isPostSecure(request) { const payload = JSON.stringify(request.body); - const ghostConfigs = await ProjectConfigs.ghost(); + const ghostSecretSignature = (await ProjectConfigs.ghost()).secret; const signatureWithDateHeader = request.headers['x-ghost-signature']; // Secret set on Ghosler but not recd. in the request headers. - if (ghostConfigs.secret && !signatureWithDateHeader) { + if (ghostSecretSignature && !signatureWithDateHeader) { logError( logTags.Express, "The 'X-Ghost-Signature' header not found in the request. Did you setup the Secret Key correctly?", @@ -327,25 +327,27 @@ export default class Miscellaneous { } /** - * Build signature with new logic for `Ghost:5.87.1` & above. - * @see https://github.com/TryGhost/Ghost/pull/20500 + * Build signature for versions below `Ghost:5.87.1`. */ - const expectedNewSignature = crypto - .createHmac('sha256', ghostConfigs.secret) - .update(`${payload}${timeStamp}`) - .digest('hex'); + const expectedOldSignature = this.#createHmac( + ghostSecretSignature, + payload, + ); /** - * Build signature for versions below `Ghost:5.87.1`. + * Build signature with new logic for `Ghost:5.87.1` & above. + * @see https://github.com/TryGhost/Ghost/pull/20500 */ - const expectedOldSignature = crypto - .createHmac('sha256', ghostConfigs.secret) - .update(payload) - .digest('hex'); + const expectedNewSignature = this.#createHmac( + ghostSecretSignature, + `${payload}${timeStamp}`, + ); - if (signature === expectedNewSignature) { - return true; - } else if (signature === expectedOldSignature) { + // Check if either of the signatures match + if ( + signature === expectedOldSignature || + signature === expectedNewSignature + ) { return true; } else { logError( @@ -374,4 +376,19 @@ export default class Miscellaneous { audience, }); } + + /** + * Creates a signature based on given inputs. + * + * @param {string} secret - The ghost secret key. + * @param {string} payload - The payload to create the hash for. + * + * @returns {string} The generated HMAC hex digest. + */ + static #createHmac(secret, payload) { + return crypto + .createHmac('sha256', secret) + .update(payload) + .digest('hex'); + } }