From d33ef0c185984d4949e41b9b15631e00814ee339 Mon Sep 17 00:00:00 2001 From: cubap Date: Tue, 13 Oct 2026 13:28:13 -0500 Subject: [PATCH] Fix normalizePort and consolidate delete handlers - Normalize port to a valid integer 1-65535, defaulting to 3002 outside the call. - Consolidate the two DELETE handlers in routes/delete.js into a single deleteRecord handler. Fixes #52, fixes #64 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- bin/tinyNode.js | 14 +++------- routes/delete.js | 69 +++++++++++++----------------------------------- 2 files changed, 22 insertions(+), 61 deletions(-) diff --git a/bin/tinyNode.js b/bin/tinyNode.js index 6f6d77d..2acf357 100644 --- a/bin/tinyNode.js +++ b/bin/tinyNode.js @@ -16,7 +16,7 @@ import http from "http" * Get port from environment and store in Express. */ -const port = normalizePort(process.env.PORT || '3002') +const port = normalizePort(process.env.PORT) || 3002 app.set('port', port) /** @@ -34,19 +34,13 @@ server.on('error', onError) server.on('listening', onListening) /** - * Normalize a port into a number, string, or false. + * Normalize a port into a valid TCP port number or false. */ function normalizePort(val) { - const port = parseInt(val, 10) + const port = Number(val) - if (isNaN(port)) { - // named pipe - return val - } - - if (port >= 0) { - // port number + if (Number.isInteger(port) && port >= 1 && port <= 65535) { return port } diff --git a/routes/delete.js b/routes/delete.js index efd70aa..d79ea89 100644 --- a/routes/delete.js +++ b/routes/delete.js @@ -5,27 +5,32 @@ import { fetchRerum } from "../rerum.js" import { isPassthroughRequest, requirePassthroughAllowed, resolveAuthorization } from "../passthrough.js" const router = express.Router() -/* Legacy delete pattern w/body. */ -router.delete('/', verifyJsonContentType, requirePassthroughAllowed, checkAccessToken, async (req, res, next) => { +async function deleteRecord(req, res) { try { - if (!req?.body || !(req.body['@id'] ?? req.body.id)) { + const id = req.params.id ?? req.body?.['@id'] ?? req.body?.id + if (!id) { const err = new Error("No record id to delete! (https://store.rerum.io/v1/API.html#delete)") err.status = 400 throw err } - const deleteBody = JSON.stringify(req.body) + const isPathDelete = Boolean(req.params.id) + const deleteURL = isPathDelete + ? `${process.env.RERUM_API_ADDR}delete/${req.params.id}` + : `${process.env.RERUM_API_ADDR}delete` const deleteOptions = { - body: deleteBody, method: 'DELETE', headers: { 'user-agent': 'Tiny-Things/1.0', 'Origin': process.env.ORIGIN, - 'Authorization': resolveAuthorization(req), - 'Content-Type' : "application/json; charset=utf-8" + 'Authorization': resolveAuthorization(req) } } - const deleteURL = `${process.env.RERUM_API_ADDR}delete` + if (!isPathDelete) { + deleteOptions.body = JSON.stringify(req.body) + deleteOptions.headers['Content-Type'] = "application/json; charset=utf-8" + } + await fetchRerum(deleteURL, deleteOptions) .then(async (resp) => { if (resp.ok) return @@ -54,51 +59,13 @@ router.delete('/', verifyJsonContentType, requirePassthroughAllowed, checkAccess console.error(err) res.status(err.status ?? 500).type('text/plain').send(err.message ?? 'An error occurred') } -}) +} + +/* Legacy delete pattern w/body. */ +router.delete('/', verifyJsonContentType, requirePassthroughAllowed, checkAccessToken, deleteRecord) /* DELETE an object by ID via the RERUM API. */ -router.delete('/:id', requirePassthroughAllowed, checkAccessToken, async (req, res, next) => { - try { - - const deleteURL = `${process.env.RERUM_API_ADDR}delete/${req.params.id}` - const deleteOptions = { - method: "DELETE", - headers: { - 'user-agent': 'Tiny-Things/1.0', - 'Origin': process.env.ORIGIN, - 'Authorization': resolveAuthorization(req), - } - } - await fetchRerum(deleteURL, deleteOptions) - .then(async (resp) => { - if (resp.ok) return - if (isPassthroughRequest(req) && (resp.status === 401 || resp.status === 403)) { - let rerumAuthMessage - try { - rerumAuthMessage = `${resp.status}: ${deleteURL} - ${await resp.text()}` - } catch (e) { - rerumAuthMessage = `${resp.status}: ${deleteURL} - A RERUM error occurred` - } - throw httpError(rerumAuthMessage, resp.status) - } - // The response from RERUM indicates a failure, likely with a specific code and textual body - let rerumErrorMessage - try { - rerumErrorMessage = `${resp.status ?? 500}: ${deleteURL} - ${await resp.text()}` - } catch (e) { - rerumErrorMessage = `500: ${deleteURL} - A RERUM error occurred` - } - const err = new Error(rerumErrorMessage) - err.status = 502 - throw err - }) - res.status(204).end() - } - catch (err) { - console.error(err) - res.status(err.status ?? 500).type('text/plain').send(err.message ?? 'An error occurred') - } -}) +router.delete('/:id', requirePassthroughAllowed, checkAccessToken, deleteRecord) router.all('/', (req, res, next) => { res.status(405).send("Method Not Allowed")