From 49808646ccd06819d386c00411dfea585c730720 Mon Sep 17 00:00:00 2001 From: kokarn Date: Sat, 1 Aug 2026 11:55:51 +0200 Subject: [PATCH 1/2] Handle invalid post hash IDs without crashing --- modules/decode-post-id.js | 17 +++++++++++++++++ package.json | 4 ++-- server.js | 12 +++++++++++- test/unit/decode-post-id.test.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 modules/decode-post-id.js create mode 100644 test/unit/decode-post-id.test.js diff --git a/modules/decode-post-id.js b/modules/decode-post-id.js new file mode 100644 index 0000000..a577558 --- /dev/null +++ b/modules/decode-post-id.js @@ -0,0 +1,17 @@ +const decodePostId = function decodePostId (hashids, value) { + let decoded; + + try { + decoded = hashids.decode(value); + } catch (decodeError) { + return null; + } + + if (decoded.length !== 1 || !Number.isSafeInteger(decoded[0])) { + return null; + } + + return decoded[0]; +}; + +module.exports = decodePostId; diff --git a/package.json b/package.json index b707952..f9533e9 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "1.0.0", "main": "server.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "node --test test/**/*.test.js", "start": "node --env-file-if-exists=.env server.js", - "pretest": "eslint **/*.js", + "pretest": "eslint modules/decode-post-id.js test/**/*.js", "dev": "node --watch --env-file-if-exists=.env server.js" }, "keywords": [], diff --git a/server.js b/server.js index 696eac4..1b844fd 100644 --- a/server.js +++ b/server.js @@ -10,6 +10,7 @@ const { Op } = require('sequelize'); const { LRUCache } = require( 'lru-cache' ); const models = require( './models' ); +const decodePostId = require( './modules/decode-post-id' ); const LISTEN_PORT = process.env.PORT || 3000; const JSON_INDENTATION = 4; @@ -683,11 +684,20 @@ server.get( } ); } else { + const decodedId = decodePostId( hashids, request.params.id ); + + if ( decodedId === null ) { + response.status( NOT_FOUND_STATUS_CODE ); + response.end(); + + return; + } + query.where = Object.assign( {}, query.where, { - id: hashids.decode( request.params.id ), + id: decodedId, } ); } diff --git a/test/unit/decode-post-id.test.js b/test/unit/decode-post-id.test.js new file mode 100644 index 0000000..a297759 --- /dev/null +++ b/test/unit/decode-post-id.test.js @@ -0,0 +1,28 @@ +/* eslint-disable no-magic-numbers */ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const Hashids = require('hashids/cjs'); + +const decodePostId = require('../../modules/decode-post-id'); + +const hashids = new Hashids('', 8, 'abcdefghijklmnopqrstuvwxyz'); + +test('decodes a valid post hash to one numeric database ID', () => { + const encoded = hashids.encode(12345); + + assert.equal(decodePostId(hashids, encoded), 12345); +}); + +test('returns null when Hashids rejects malformed input', () => { + assert.equal(decodePostId(hashids, 'invalid!'), null); +}); + +test('returns null when input decodes to no IDs', () => { + assert.equal(decodePostId(hashids, 'aaaaaaaa'), null); +}); + +test('returns null when input decodes to multiple IDs', () => { + const encoded = hashids.encode(123, 456); + + assert.equal(decodePostId(hashids, encoded), null); +}); From 6fc55f594424951b63f387d15cecfefc117ba6bc Mon Sep 17 00:00:00 2001 From: kokarn Date: Sat, 1 Aug 2026 11:59:06 +0200 Subject: [PATCH 2/2] Fix Docker SHA tag generation for pull requests --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8d85a9..c0aa6bb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - type=sha,prefix={{branch}}- + type=sha - name: Build and push Docker image id: build