From 7f872fe13a31a68a8a8b2a84e53ef4361c2f4f88 Mon Sep 17 00:00:00 2001 From: codfish Date: Sun, 8 Mar 2026 18:43:40 -0400 Subject: [PATCH 1/3] fix: make security and DX improvements --- .dockerignore | 9 +++++++++ Dockerfile | 7 ++++++- README.md | 2 +- server.js | 12 +++++++++--- tsconfig.json | 5 +---- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/.dockerignore b/.dockerignore index 3c3629e..654fe96 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,10 @@ +.git +.github +.nvmrc +dist +examples node_modules +README.md +ts.png +docker-compose.yml +eslint.config.js diff --git a/Dockerfile b/Dockerfile index f564d32..b64d379 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,15 @@ FROM node:24-slim ENV PNPM_HOME="/pnpm" +ENV COREPACK_HOME="/corepack" ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable +RUN apt-get update && apt-get install -y --no-install-recommends tini && rm -rf /var/lib/apt/lists/* RUN mkdir /app WORKDIR /app COPY package.json pnpm-lock.yaml ./ +RUN corepack install RUN pnpm install --frozen-lockfile --prod # copy in files @@ -17,5 +20,7 @@ COPY ./tsconfig.json \ EXPOSE 3000 ENV PORT=3000 +RUN chown -R node:node /app /pnpm /corepack +USER node -ENTRYPOINT [ "pnpm", "start" ] +ENTRYPOINT [ "tini", "--", "pnpm", "start" ] diff --git a/README.md b/README.md index 8696e88..9ee503d 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ for usage... > It's recommended to specify the tag of the image you want rather than using the latest image, which might break. Image > tags are based off of the [release versions for json-server](https://github.com/typicode/json-server/releases). > However there is not an image for every version. See the available versions -> [here](https://hub.docker.com/r/codfish/json-server/tags). +> [on Docker Hub](https://hub.docker.com/r/codfish/json-server/tags). This project actually dogfoods itself. View the [docker-compose.yml](./docker-compose.yml) & the [examples/](./examples/) directory to see various usage examples. Also visit the diff --git a/server.js b/server.js index f28b89d..fafc231 100755 --- a/server.js +++ b/server.js @@ -17,8 +17,8 @@ if (await fs.exists('.cache')) { } if (extraDeps && cache.trim() !== extraDeps) { - const command = `pnpm add --save-false ${process.env.DEPENDENCIES}`; - await $([command]); + const deps = process.env.DEPENDENCIES.split(/\s+/).filter(Boolean); + await $`pnpm add ${deps}`; await fs.writeFile('.cache', extraDeps); } @@ -67,7 +67,13 @@ if (await fs.pathExists('./dist/public')) { staticDirs.push('dist/public'); } if (process.env.STATIC) { - staticDirs.push(process.env.STATIC); + const staticPath = process.env.STATIC; + if (staticPath.includes('..')) { + // eslint-disable-next-line no-console + console.error(`STATIC path must not contain '..'. Got: ${staticPath}`); + process.exit(1); + } + staticDirs.push(staticPath); } const app = createApp(db, { diff --git a/tsconfig.json b/tsconfig.json index 1e9923a..7927983 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,10 @@ { "include": ["**/*.ts", "**/*.js"], - "exclude": ["dist", "examples", "node_modules"], + "exclude": ["dist/**", "examples/**", "node_modules/**"], "compilerOptions": { "target": "es2022", "module": "nodenext", "moduleResolution": "nodenext", - "paths": { - "@/*": ["./api/*"] - }, "allowJs": true, "checkJs": false, "outDir": "./dist", From a42dd8418ccb10981ec343d87cbabbb911329e5f Mon Sep 17 00:00:00 2001 From: codfish Date: Sun, 8 Mar 2026 19:48:43 -0400 Subject: [PATCH 2/3] fix: cast ids to strings; add static example --- README.md | 12 +++++- db.js | 4 +- docker-compose.yml | 13 +++++++ examples/deps/db.js | 2 +- examples/json/db.json | 60 +++++++++++++++--------------- examples/middlewares/db.json | 60 +++++++++++++++--------------- examples/static/db.json | 14 +++++++ examples/static/public/image.png | Bin 0 -> 47776 bytes examples/static/public/index.html | 23 ++++++++++++ 9 files changed, 124 insertions(+), 64 deletions(-) create mode 100644 examples/static/db.json create mode 100644 examples/static/public/image.png create mode 100644 examples/static/public/index.html diff --git a/README.md b/README.md index 9ee503d..4a18355 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ This project actually dogfoods itself. View the [docker-compose.yml](./docker-co - [Typescript](./examples/typescript/) - [Mount in additional files](./examples/support-files/) - [Custom middleware](./examples/middlewares/) +- [Static files](./examples/static/) ### Docker Compose (Recommended) @@ -137,6 +138,9 @@ See all the [available options below](#options). ### Important Usage Notes +- **IDs must be strings.** json-server v1 uses strict equality (`===`) to match URL params against record IDs. Since URL + params are always strings, integer IDs will never match on individual resource lookups (e.g., `GET /users/1`). Use + string IDs like `"1"` or UUIDs. - All mounted files should use **ESM syntax** (`import`/`export default`). - All files should be mounted into the `/app` directory in the container. - The following files are special and will "just work" when **mounted over**: @@ -233,9 +237,14 @@ supported: | Option | Description | Default | | -------------- | ------------------------------------------------------------------------------------ | ------- | | `DEPENDENCIES` | Install extra npm dependencies in the container for you to use in your server files. | — | -| `STATIC` | Set static files directory | — | +| `STATIC` | Serve an additional static files directory (`./public` is always served) | — | | `PORT` | Set the port the server listens on inside the container. | 3000 | +> [!CAUTION] +> +> The `DEPENDENCIES` env var runs `pnpm add` with whatever packages you specify. A malicious package's install script +> will execute inside the container. Only use packages you trust. + ## Query Parameters json-server v1 supports the following query parameters: @@ -272,6 +281,7 @@ to a directory in [examples/](./examples/). | `docker-compose up json-db` | 9997 | Plain JSON database file | | `docker-compose up middlewares` | 9996 | Custom middleware that sets response headers | | `docker-compose up deps` | 9995 | Extra dependencies installed via `DEPENDENCIES` envar | +| `docker-compose up static` | 9993 | Custom public directory with static HTML | | `docker-compose up dags` | 9994 | Supporting files mounted alongside the db | Run all examples: diff --git a/db.js b/db.js index 07f7490..fd47eca 100644 --- a/db.js +++ b/db.js @@ -2,8 +2,8 @@ import { faker } from '@faker-js/faker'; export default () => ({ users: faker.helpers.multiple( - idx => ({ - id: idx, + () => ({ + id: faker.string.uuid(), name: faker.person.fullName(), username: faker.internet.username(), email: faker.internet.email(), diff --git a/docker-compose.yml b/docker-compose.yml index 9b26790..c561561 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -62,6 +62,19 @@ services: VIRTUAL_HOST: deps.json-server.docker DEPENDENCIES: chance@1 node-emoji@1 + static: + build: . + volumes: + - ./server.js:/app/server.js:delegated + - ./middleware.js:/app/middleware.js:delegated + - ./examples/static/db.json:/app/db.json + - ./examples/static/public:/app/public + ports: + - 9993:9993 + environment: + PORT: 9993 + VIRTUAL_HOST: static.json-server.docker + dags: build: . volumes: diff --git a/examples/deps/db.js b/examples/deps/db.js index 700c420..026883e 100644 --- a/examples/deps/db.js +++ b/examples/deps/db.js @@ -8,7 +8,7 @@ export default () => ({ const animal = chance.animal({ type: 'pet' }).replace(/s$/, '').split(' ').pop().toLowerCase(); return { - id: idx + 1, + id: `${idx + 1}`, animal, emoji: emoji.find(animal)?.emoji || '🦄', name: chance.name({ middle: true }), diff --git a/examples/json/db.json b/examples/json/db.json index 1c67cee..fdbeb0f 100644 --- a/examples/json/db.json +++ b/examples/json/db.json @@ -1,92 +1,92 @@ { "todos": [ { - "userId": 1, - "id": 1, + "userId": "1", + "id": "1", "title": "delectus aut autem", "completed": false }, { - "userId": 1, - "id": 2, + "userId": "1", + "id": "2", "title": "quis ut nam facilis et officia qui", "completed": false }, { - "userId": 1, - "id": 3, + "userId": "1", + "id": "3", "title": "fugiat veniam minus", "completed": false }, { - "userId": 1, - "id": 4, + "userId": "1", + "id": "4", "title": "et porro tempora", "completed": true }, { - "userId": 1, - "id": 5, + "userId": "1", + "id": "5", "title": "laboriosam mollitia et enim quasi adipisci quia provident illum", "completed": false }, { - "userId": 1, - "id": 6, + "userId": "1", + "id": "6", "title": "qui ullam ratione quibusdam voluptatem quia omnis", "completed": false }, { - "userId": 1, - "id": 7, + "userId": "1", + "id": "7", "title": "illo expedita consequatur quia in", "completed": false }, { - "userId": 1, - "id": 8, + "userId": "1", + "id": "8", "title": "quo adipisci enim quam ut ab", "completed": true }, { - "userId": 1, - "id": 9, + "userId": "1", + "id": "9", "title": "molestiae perspiciatis ipsa", "completed": false }, { - "userId": 1, - "id": 10, + "userId": "1", + "id": "10", "title": "illo est ratione doloremque quia maiores aut", "completed": true }, { - "userId": 1, - "id": 11, + "userId": "1", + "id": "11", "title": "vero rerum temporibus dolor", "completed": true }, { - "userId": 1, - "id": 12, + "userId": "1", + "id": "12", "title": "ipsa repellendus fugit nisi", "completed": true }, { - "userId": 1, - "id": 13, + "userId": "1", + "id": "13", "title": "et doloremque nulla", "completed": false }, { - "userId": 1, - "id": 14, + "userId": "1", + "id": "14", "title": "repellendus sunt dolores architecto voluptatum", "completed": true }, { - "userId": 1, - "id": 15, + "userId": "1", + "id": "15", "title": "ab voluptatum amet voluptas", "completed": true } diff --git a/examples/middlewares/db.json b/examples/middlewares/db.json index ef2b404..abfc34a 100644 --- a/examples/middlewares/db.json +++ b/examples/middlewares/db.json @@ -1,78 +1,78 @@ { "albums": [ { - "userId": 1, - "id": 1, + "userId": "1", + "id": "1", "title": "quidem molestiae enim" }, { - "userId": 1, - "id": 2, + "userId": "1", + "id": "2", "title": "sunt qui excepturi placeat culpa" }, { - "userId": 1, - "id": 3, + "userId": "1", + "id": "3", "title": "omnis laborum odio" }, { - "userId": 1, - "id": 4, + "userId": "1", + "id": "4", "title": "non esse culpa molestiae omnis sed optio" }, { - "userId": 1, - "id": 5, + "userId": "1", + "id": "5", "title": "eaque aut omnis a" }, { - "userId": 1, - "id": 6, + "userId": "1", + "id": "6", "title": "natus impedit quibusdam illo est" }, { - "userId": 1, - "id": 7, + "userId": "1", + "id": "7", "title": "quibusdam autem aliquid et et quia" }, { - "userId": 1, - "id": 8, + "userId": "1", + "id": "8", "title": "qui fuga est a eum" }, { - "userId": 1, - "id": 9, + "userId": "1", + "id": "9", "title": "saepe unde necessitatibus rem" }, { - "userId": 1, - "id": 10, + "userId": "1", + "id": "10", "title": "distinctio laborum qui" }, { - "userId": 2, - "id": 11, + "userId": "2", + "id": "11", "title": "quam nostrum impedit mollitia quod et dolor" }, { - "userId": 2, - "id": 12, + "userId": "2", + "id": "12", "title": "consequatur autem doloribus natus consectetur" }, { - "userId": 2, - "id": 13, + "userId": "2", + "id": "13", "title": "ab rerum non rerum consequatur ut ea unde" }, { - "userId": 2, - "id": 14, + "userId": "2", + "id": "14", "title": "ducimus molestias eos animi atque nihil" }, { - "userId": 2, - "id": 15, + "userId": "2", + "id": "15", "title": "ut pariatur rerum ipsum natus repellendus praesentium" } ] diff --git a/examples/static/db.json b/examples/static/db.json new file mode 100644 index 0000000..34c6b8f --- /dev/null +++ b/examples/static/db.json @@ -0,0 +1,14 @@ +{ + "posts": [ + { + "id": "1", + "title": "Hello World", + "body": "Welcome to json-server" + }, + { + "id": "2", + "title": "Second Post", + "body": "This is another post" + } + ] +} diff --git a/examples/static/public/image.png b/examples/static/public/image.png new file mode 100644 index 0000000000000000000000000000000000000000..f1b136b67551e6c96afb29efc17731e5b940c24e GIT binary patch literal 47776 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 F{U0M-pOXLp literal 0 HcmV?d00001 diff --git a/examples/static/public/index.html b/examples/static/public/index.html new file mode 100644 index 0000000..4b327c2 --- /dev/null +++ b/examples/static/public/index.html @@ -0,0 +1,23 @@ + + + + + + JSON Server + + + +

JSON Server Custom index.html

+

Your mock API is running. Try these endpoints:

+ + + From a39fcfc869789c9c88160d2f55e9d05ee4f6a2d9 Mon Sep 17 00:00:00 2001 From: codfish Date: Sun, 8 Mar 2026 20:11:17 -0400 Subject: [PATCH 3/3] fix: prevent absolute static paths --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index fafc231..3f25bc1 100755 --- a/server.js +++ b/server.js @@ -68,9 +68,9 @@ if (await fs.pathExists('./dist/public')) { } if (process.env.STATIC) { const staticPath = process.env.STATIC; - if (staticPath.includes('..')) { + if (staticPath.includes('..') || staticPath.startsWith('/')) { // eslint-disable-next-line no-console - console.error(`STATIC path must not contain '..'. Got: ${staticPath}`); + console.error(`STATIC path must be relative and not contain '..'. Got: ${staticPath}`); process.exit(1); } staticDirs.push(staticPath);