From 2ec4a2b3717f61660728324b51800077a0f732f5 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sat, 3 Oct 2026 11:45:26 +0700 Subject: [PATCH] refactor(renderer)!: drop the API token from the internal renderer The renderer now runs only on the compose network with no published port or domain, so a shared bearer token adds nothing. The renderer no longer checks Authorization or requires API_TOKEN in production, and the bot no longer sends a token. BREAKING CHANGE: WHEELOFNAMES_API_TOKEN and the renderer's API_TOKEN are removed. Never publish the renderer's port: its API is unauthenticated. --- .env.example | 3 --- compose.yml | 6 ++--- docs/deploy-coolify-selfhosted.md | 12 +++------ internal/modules/random/gacha_command_test.go | 5 ++-- internal/modules/random/handlers_test.go | 6 ++--- .../modules/random/wheelofnames_api_client.go | 17 +++++-------- .../random/wheelofnames_api_client_test.go | 13 +++------- renderer/.env.example | 2 -- renderer/README.md | 6 ++--- renderer/docs/deployment.md | 11 +++----- renderer/docs/miti99bot-integration.md | 9 ++++--- renderer/scripts/api-smoke.js | 11 -------- renderer/src/config.js | 11 -------- renderer/src/lib/bearer-auth.js | 7 ------ renderer/src/routes/gacha.js | 5 ---- renderer/src/routes/gif.js | 5 ---- renderer/test/config.test.js | 11 -------- renderer/test/gacha-route.test.js | 19 -------------- renderer/test/gif-route.test.js | 25 ------------------- 19 files changed, 30 insertions(+), 154 deletions(-) delete mode 100644 renderer/src/lib/bearer-auth.js diff --git a/.env.example b/.env.example index dc090e1..100de08 100644 --- a/.env.example +++ b/.env.example @@ -43,9 +43,6 @@ LOL_PANDASCORE_TOKEN= # set it only when running the bot outside compose. /gacha calls /api/gacha on # the same service. Leave blank to fall back to text selection. WHEELOFNAMES_API_URL= -# Bearer token shared with the renderer; compose passes it to the renderer as -# API_TOKEN. Required for the renderer to start. -WHEELOFNAMES_API_TOKEN= # ====================== Leave UNSET on self-host ================== # Defaults are correct for self-host: diff --git a/compose.yml b/compose.yml index b430389..7c77c7b 100644 --- a/compose.yml +++ b/compose.yml @@ -19,7 +19,6 @@ services: # platform-level value cannot point the bot elsewhere; /gacha and # /genshin derive their endpoints from it. WHEELOFNAMES_API_URL: http://renderer:3000/api/gif - WHEELOFNAMES_API_TOKEN: ${WHEELOFNAMES_API_TOKEN:-} # Shared bearer token; the renderer uses it as API_TOKEN # SOURCE_COMMIT is intentionally not declared here. Coolify provides it # at runtime via its generated env file; declaring it here with Compose # interpolation can override the runtime value with an empty string. @@ -44,8 +43,8 @@ services: # Animation renderer (Node + Remotion + headless Chrome) from renderer/. # Internal only: the bot reaches it over the compose network, so it has no - # published port and no public domain. Without WHEELOFNAMES_API_TOKEN it - # refuses to start in production, and the bot falls back to text replies. + # published port, no public domain, and no auth token. Never publish a port + # or attach a domain to it — its API is unauthenticated. renderer: build: context: ./renderer @@ -54,7 +53,6 @@ services: NODE_ENV: production HOST: 0.0.0.0 PORT: "3000" - API_TOKEN: ${WHEELOFNAMES_API_TOKEN:-} MAX_CONCURRENT_RENDERS: ${MAX_CONCURRENT_RENDERS:-1} RENDER_TIMEOUT_MS: ${RENDER_TIMEOUT_MS:-15000} MAX_OPTIONS: ${MAX_OPTIONS:-32} diff --git a/docs/deploy-coolify-selfhosted.md b/docs/deploy-coolify-selfhosted.md index ad67a8d..023ffd0 100644 --- a/docs/deploy-coolify-selfhosted.md +++ b/docs/deploy-coolify-selfhosted.md @@ -37,7 +37,6 @@ Copy [`.env.example`](../.env.example) → `.env` (gitignored) and fill in. | `STICKER_PACK_NAME` | optional | set `/addsticker` writes to; default `miti99_by_miti99bot`. See [sticker packs](sticker-packs.md) | | `LOL_PANDASCORE_TOKEN` | ✅ for lol module | PandaScore API token (free tier) — secret, never logged; without it every `/lol*` fetch fails (stale cache may still serve briefly) | | `WHEELOFNAMES_API_URL` | leave unset | fixed by `compose.yml` to the bundled renderer (`http://renderer:3000/api/gif`); a Coolify value is ignored | -| `WHEELOFNAMES_API_TOKEN` | ✅ for animations | bearer token shared by the bot and the bundled renderer (its `API_TOKEN`) — secret; unset = the renderer refuses to start and the animated commands reply with text | | `LOG_LEVEL` | optional | `debug`, `info` (default), `warn`, or `error`; logs are JSON on stdout | | `GOLD_VNAPP_API_KEY` | leave unset | VNAppMob key; unset = the gold module fetches one and caches it in MongoDB | | `KV_PROVIDER` | leave unset | `memory` or `mongodb`; unset = `mongodb` when `MONGO_URL` is set, otherwise `memory` | @@ -57,12 +56,9 @@ has no webhook. [`renderer/`](../renderer/README.md) (Remotion and headless Chrome). `compose.yml` deploys it as a second service, `renderer`, next to the bot. It is internal only: the bot reaches it at `http://renderer:3000/api/gif` over the -compose network, so it needs no domain and publishes no port. The only setting -is the shared token: - -```env -WHEELOFNAMES_API_TOKEN= -``` +compose network, so it needs no domain, publishes no port, and takes no auth +token. Its API is unauthenticated, so never publish a port or attach a domain +to it. Renderer tuning (`MAX_CONCURRENT_RENDERS`, `RENDER_TIMEOUT_MS`, `MAX_OPTIONS`, `MAX_OPTION_CHARS`) can be set in Coolify too; the defaults are in @@ -74,7 +70,7 @@ implements the same `/api/gif` contract. The bot sends outbound HTTP only; no public bot ingress is required. Remote renders use `512px`, `20fps`, and `7` seconds total by default. If the renderer -is unset, unavailable, unauthorized, or returns a non-GIF response, +is unset, unavailable, or returns a non-GIF response, `/wheelofnames` falls back to the same plain text winner reply as `/random`. Successful GIF replies include the result behind Telegram spoiler formatting. diff --git a/internal/modules/random/gacha_command_test.go b/internal/modules/random/gacha_command_test.go index 524ceea..1f870c9 100644 --- a/internal/modules/random/gacha_command_test.go +++ b/internal/modules/random/gacha_command_test.go @@ -67,7 +67,6 @@ func TestGacha_UsesRemoteAPIWhenConfigured(t *testing.T) { })) defer server.Close() t.Setenv(wheelOfNamesAPIURLEnv, server.URL+"/api/gif") - t.Setenv(wheelOfNamesAPITokenEnv, "remote-token") rb := installRandom(t, 999) rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/gacha 4* Pho")) @@ -75,8 +74,8 @@ func TestGacha_UsesRemoteAPIWhenConfigured(t *testing.T) { if gotPath != "/api/gacha" { t.Fatalf("path = %q, want /api/gacha", gotPath) } - if gotAuthorization != "Bearer remote-token" { - t.Fatalf("Authorization = %q, want bearer token", gotAuthorization) + if gotAuthorization != "" { + t.Fatalf("Authorization = %q, want none", gotAuthorization) } want := gachaAPIRequest{Label: "Pho", Rarity: 4, FPS: gachaRemoteFPS, Width: gachaRemoteWidth} if got != want { diff --git a/internal/modules/random/handlers_test.go b/internal/modules/random/handlers_test.go index d6e1b10..ec338a3 100644 --- a/internal/modules/random/handlers_test.go +++ b/internal/modules/random/handlers_test.go @@ -132,7 +132,6 @@ func TestWheelOfNames_UsesRemoteAPIWhenConfigured(t *testing.T) { })) defer server.Close() t.Setenv(wheelOfNamesAPIURLEnv, server.URL+"/api/gif") - t.Setenv(wheelOfNamesAPITokenEnv, "remote-token") rb := installRandom(t, 999) rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/wheelofnames Alice, Bob, Carol")) @@ -140,8 +139,8 @@ func TestWheelOfNames_UsesRemoteAPIWhenConfigured(t *testing.T) { if calls != 1 { t.Fatalf("remote calls = %d, want 1", calls) } - if gotAuthorization != "Bearer remote-token" { - t.Fatalf("Authorization = %q, want bearer token", gotAuthorization) + if gotAuthorization != "" { + t.Fatalf("Authorization = %q, want none", gotAuthorization) } if !slices.Equal(got.Options, []string{"Alice", "Bob", "Carol"}) { t.Fatalf("options = %#v, want parsed options", got.Options) @@ -193,7 +192,6 @@ func TestWheelOfNames_RemoteFailureFallsBackToRandomReply(t *testing.T) { })) defer server.Close() t.Setenv(wheelOfNamesAPIURLEnv, server.URL+"/api/gif") - t.Setenv(wheelOfNamesAPITokenEnv, "remote-token") rb := installRandom(t, 999) rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/wheelofnames Alice")) diff --git a/internal/modules/random/wheelofnames_api_client.go b/internal/modules/random/wheelofnames_api_client.go index fe2780b..ab55181 100644 --- a/internal/modules/random/wheelofnames_api_client.go +++ b/internal/modules/random/wheelofnames_api_client.go @@ -17,10 +17,10 @@ import ( const ( // The standard renderer is the renderer/ service in this repository, wired - // in by compose.yml. Operators may point this to any service that + // in by compose.yml and reachable only on the compose network, so requests + // carry no credentials. Operators may point this to any service that // implements the same /api/gif contract. - wheelOfNamesAPIURLEnv = "WHEELOFNAMES_API_URL" - wheelOfNamesAPITokenEnv = "WHEELOFNAMES_API_TOKEN" + wheelOfNamesAPIURLEnv = "WHEELOFNAMES_API_URL" wheelRemoteDurationMs = 6000 wheelRemoteHoldMs = 1000 @@ -35,9 +35,8 @@ const ( var errWheelAPINotConfigured = errors.New("wheelofnames api not configured") type wheelAPIClient struct { - HTTP *http.Client - URL string - Token string + HTTP *http.Client + URL string } type wheelAPIRequest struct { @@ -59,8 +58,7 @@ type wheelAnimation struct { func newWheelAPIClientFromEnv() wheelAPIClient { return wheelAPIClient{ - URL: strings.TrimSpace(os.Getenv(wheelOfNamesAPIURLEnv)), - Token: strings.TrimSpace(os.Getenv(wheelOfNamesAPITokenEnv)), + URL: strings.TrimSpace(os.Getenv(wheelOfNamesAPIURLEnv)), } } @@ -102,9 +100,6 @@ func (c wheelAPIClient) post(ctx context.Context, endpoint *url.URL, body []byte } req.Header.Set("Accept", mediaType) req.Header.Set("Content-Type", "application/json") - if c.Token != "" { - req.Header.Set("Authorization", "Bearer "+c.Token) - } resp, err := c.httpClient().Do(req) if err != nil { diff --git a/internal/modules/random/wheelofnames_api_client_test.go b/internal/modules/random/wheelofnames_api_client_test.go index 7c2a65a..50cb6b9 100644 --- a/internal/modules/random/wheelofnames_api_client_test.go +++ b/internal/modules/random/wheelofnames_api_client_test.go @@ -14,7 +14,6 @@ import ( func TestWheelAPIClient_RenderValidRequest(t *testing.T) { var got wheelAPIRequest var gotAccept string - var gotAuthorization string var gotContentType string var gotMethod string var gotPath string @@ -22,7 +21,6 @@ func TestWheelAPIClient_RenderValidRequest(t *testing.T) { gotMethod = r.Method gotPath = r.URL.Path gotAccept = r.Header.Get("Accept") - gotAuthorization = r.Header.Get("Authorization") gotContentType = r.Header.Get("Content-Type") if err := json.NewDecoder(r.Body).Decode(&got); err != nil { t.Errorf("Decode request body: %v", err) @@ -33,9 +31,8 @@ func TestWheelAPIClient_RenderValidRequest(t *testing.T) { defer server.Close() client := wheelAPIClient{ - HTTP: server.Client(), - URL: server.URL + "/api/gif", - Token: "secret-token", + HTTP: server.Client(), + URL: server.URL + "/api/gif", } data, err := client.Render(context.Background(), []string{"alice", "bob", "carol"}, 1) if err != nil { @@ -56,9 +53,6 @@ func TestWheelAPIClient_RenderValidRequest(t *testing.T) { if gotContentType != "application/json" { t.Fatalf("Content-Type = %q, want application/json", gotContentType) } - if gotAuthorization != "Bearer secret-token" { - t.Fatalf("Authorization = %q, want bearer token", gotAuthorization) - } if !slices.Equal(got.Options, []string{"alice", "bob", "carol"}) { t.Fatalf("options = %#v, want original options", got.Options) } @@ -68,7 +62,8 @@ func TestWheelAPIClient_RenderValidRequest(t *testing.T) { assertWheelRemoteDefaults(t, got) } -func TestWheelAPIClient_RenderWithoutTokenOmitsAuthorization(t *testing.T) { +// The renderer is internal to the compose network; the bot sends no credentials. +func TestWheelAPIClient_RenderSendsNoAuthorization(t *testing.T) { var gotAuthorization string server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotAuthorization = r.Header.Get("Authorization") diff --git a/renderer/.env.example b/renderer/.env.example index 23d889d..c19d09f 100644 --- a/renderer/.env.example +++ b/renderer/.env.example @@ -6,5 +6,3 @@ MAX_CONCURRENT_RENDERS=1 RENDER_TIMEOUT_MS=15000 MAX_OPTIONS=32 MAX_OPTION_CHARS=40 -# Required in production. Clients must send Authorization: Bearer . -API_TOKEN=change-me diff --git a/renderer/README.md b/renderer/README.md index f5f9f3f..0609dfd 100644 --- a/renderer/README.md +++ b/renderer/README.md @@ -12,7 +12,6 @@ animations with pack-cards. POST /api/gif Content-Type: application/json Accept: image/gif -Authorization: Bearer change-me ``` ```json @@ -41,7 +40,6 @@ Response is `image/gif` with winner metadata headers: POST /api/gacha Content-Type: application/json Accept: video/mp4 -Authorization: Bearer change-me ``` ```json @@ -180,10 +178,10 @@ dependencies, and FFmpeg/compositor support. ```sh docker build -t wheelofnames . -docker run --rm -p 3000:3000 -e API_TOKEN=change-me wheelofnames +docker run --rm -p 3000:3000 wheelofnames ``` Recommended starting resources: 1-2 vCPU and 1-2 GB RAM, with `MAX_CONCURRENT_RENDERS=1`. `RENDER_TIMEOUT_MS` defaults to `15000` and is raised to Remotion's `7000ms` browser timeout floor when configured lower. -`API_TOKEN` is required when `NODE_ENV=production`. +The API has no authentication; publish its port only on a trusted network. diff --git a/renderer/docs/deployment.md b/renderer/docs/deployment.md index 07c9ac5..dd7196c 100644 --- a/renderer/docs/deployment.md +++ b/renderer/docs/deployment.md @@ -3,9 +3,9 @@ ## miti99bot compose The root `compose.yml` builds this folder as the `renderer` service and points -the bot at it over the compose network. Only `WHEELOFNAMES_API_TOKEN` needs a -value there; it becomes `API_TOKEN` below. The rest of this page covers running -the service on its own. +the bot at it over the compose network. The API has no authentication: it is +reachable only from inside that network, so never publish its port or attach a +domain to it. The rest of this page covers running the service on its own. ## Recommendation @@ -37,7 +37,6 @@ MAX_CONCURRENT_RENDERS=1 RENDER_TIMEOUT_MS=15000 MAX_OPTIONS=32 MAX_OPTION_CHARS=40 -API_TOKEN=change-me ``` The root `compose.yml` forwards the tuning values with `${VAR:-default}` @@ -54,9 +53,6 @@ do not need to download Chrome Headless Shell on first render. `RENDER_TIMEOUT_MS` is a total render timeout. Values below `7000` are raised to `7000` because Remotion's browser timeout has that minimum. -Set `API_TOKEN` for every production deployment. The server refuses to start -with `NODE_ENV=production` unless the token is configured. - ## Health ```sh @@ -68,7 +64,6 @@ curl http://localhost:3000/api/healthz ```sh curl -X POST http://localhost:3000/api/gif \ -H 'content-type: application/json' \ - -H 'authorization: Bearer change-me' \ --output wheel.gif \ --data '{"options":["alice","bob","carol"],"winnerIndex":1}' ``` diff --git a/renderer/docs/miti99bot-integration.md b/renderer/docs/miti99bot-integration.md index 830592f..6ed4046 100644 --- a/renderer/docs/miti99bot-integration.md +++ b/renderer/docs/miti99bot-integration.md @@ -1,8 +1,9 @@ # miti99bot Integration miti99bot's `/wheelofnames` renders its wheel with this service, configured -by `WHEELOFNAMES_API_URL` (pointing at `/api/gif`) and -`WHEELOFNAMES_API_TOKEN`. Winner handling stays explicit: +by `WHEELOFNAMES_API_URL` (pointing at `/api/gif`). The service is internal to +the compose network, so requests carry no credentials. Winner handling stays +explicit: 1. The bot parses the comma-separated options. 2. It chooses `winnerIndex` itself. @@ -14,7 +15,7 @@ by `WHEELOFNAMES_API_URL` (pointing at `/api/gif`) and ## Request -Send `Authorization: Bearer ` with the JSON body. +Send the JSON body: ```json { @@ -41,7 +42,7 @@ winner selection is used. ## Gacha -`/gacha` in miti99bot calls `POST /api/gacha` on the same service and token. +`/gacha` in miti99bot calls `POST /api/gacha` on the same service. The bot derives the endpoint from `WHEELOFNAMES_API_URL` by replacing its last path segment (`/api/gif` becomes `/api/gacha`), picks the result and rarity itself, and sends the MP4 with `sendAnimation`. On any failure it falls back to diff --git a/renderer/scripts/api-smoke.js b/renderer/scripts/api-smoke.js index a84e84f..6acec4d 100644 --- a/renderer/scripts/api-smoke.js +++ b/renderer/scripts/api-smoke.js @@ -1,13 +1,11 @@ import {buildServer} from '../src/server.js'; const config = { - apiToken: 'smoke-token', host: '127.0.0.1', maxConcurrentRenders: 1, maxOptionChars: 40, maxOptions: 32, port: 0, - requiresApiToken: true, renderTimeoutMs: 30000, }; @@ -17,9 +15,6 @@ try { const response = await app.inject({ method: 'POST', url: '/api/gif', - headers: { - authorization: 'Bearer smoke-token', - }, payload: { durationMs: 3000, fps: 12, @@ -49,9 +44,6 @@ try { const gacha = await app.inject({ method: 'POST', url: '/api/gacha', - headers: { - authorization: 'Bearer smoke-token', - }, payload: {label: 'Bún bò', rarity: 5}, }); @@ -69,9 +61,6 @@ try { const genshin = await app.inject({ method: 'POST', url: '/api/genshin', - headers: { - authorization: 'Bearer smoke-token', - }, payload: {label: 'Bún bò', rarity: 5}, }); diff --git a/renderer/src/config.js b/renderer/src/config.js index 50890a3..3ecf93b 100644 --- a/renderer/src/config.js +++ b/renderer/src/config.js @@ -8,8 +8,6 @@ export const minRenderTimeoutMs = 7000; * @property {number} renderTimeoutMs * @property {number} maxOptions * @property {number} maxOptionChars - * @property {string | undefined} apiToken - * @property {boolean} requiresApiToken */ /** @@ -31,13 +29,6 @@ const parsePositiveInt = (value, fallback) => { * @returns {AppConfig} */ export const loadConfig = (env = process.env) => { - const apiToken = env.API_TOKEN || undefined; - const requiresApiToken = env.NODE_ENV === 'production' || env.REQUIRE_API_TOKEN === 'true'; - - if (requiresApiToken && !apiToken) { - throw new Error('API_TOKEN is required when NODE_ENV=production or REQUIRE_API_TOKEN=true'); - } - return { host: env.HOST || '0.0.0.0', port: parsePositiveInt(env.PORT, 3000), @@ -48,7 +39,5 @@ export const loadConfig = (env = process.env) => { ), maxOptions: parsePositiveInt(env.MAX_OPTIONS, 32), maxOptionChars: parsePositiveInt(env.MAX_OPTION_CHARS, 40), - apiToken, - requiresApiToken, }; }; diff --git a/renderer/src/lib/bearer-auth.js b/renderer/src/lib/bearer-auth.js deleted file mode 100644 index 454b92f..0000000 --- a/renderer/src/lib/bearer-auth.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @param {import('fastify').FastifyRequest} request - * @param {string | undefined} apiToken - * @returns {boolean} true when no token is configured or the request carries it. - */ -export const isAuthorized = (request, apiToken) => - !apiToken || request.headers.authorization === `Bearer ${apiToken}`; diff --git a/renderer/src/routes/gacha.js b/renderer/src/routes/gacha.js index 79b8f5e..b485a33 100644 --- a/renderer/src/routes/gacha.js +++ b/renderer/src/routes/gacha.js @@ -1,6 +1,5 @@ import {randomInt} from 'node:crypto'; import {ZodError} from 'zod'; -import {isAuthorized} from '../lib/bearer-auth.js'; import {isRenderTimeoutError} from '../lib/render-errors.js'; import {maxGachaSeed, parseGachaRequest} from '../schemas/gacha-request.js'; @@ -27,10 +26,6 @@ import {maxGachaSeed, parseGachaRequest} from '../schemas/gacha-request.js'; export const registerGachaRoute = async (app, deps) => { const name = deps.name ?? 'gacha'; app.post(`/api/${name}`, async (request, reply) => { - if (!isAuthorized(request, deps.config.apiToken)) { - return reply.code(401).send({error: 'unauthorized'}); - } - let gachaRequest; try { gachaRequest = parseGachaRequest(request.body, {maxOptionChars: deps.config.maxOptionChars}, () => diff --git a/renderer/src/routes/gif.js b/renderer/src/routes/gif.js index 438e9fb..038a91d 100644 --- a/renderer/src/routes/gif.js +++ b/renderer/src/routes/gif.js @@ -1,5 +1,4 @@ import {ZodError} from 'zod'; -import {isAuthorized} from '../lib/bearer-auth.js'; import {isRenderTimeoutError} from '../lib/render-errors.js'; import {pickWinnerIndex} from '../lib/winner.js'; import {parseWheelRequest} from '../schemas/wheel-request.js'; @@ -31,10 +30,6 @@ const formatValidationError = (issues) => ({ */ export const registerGifRoute = async (app, deps) => { app.post('/api/gif', async (request, reply) => { - if (!isAuthorized(request, deps.config.apiToken)) { - return reply.code(401).send({error: 'unauthorized'}); - } - let wheelRequest; try { wheelRequest = parseWheelRequest( diff --git a/renderer/test/config.test.js b/renderer/test/config.test.js index 1d0d2ae..f586ce1 100644 --- a/renderer/test/config.test.js +++ b/renderer/test/config.test.js @@ -7,15 +7,4 @@ describe('loadConfig', () => { expect(config.renderTimeoutMs).toBe(minRenderTimeoutMs); }); - - test('requires API_TOKEN in production', () => { - expect(() => loadConfig({NODE_ENV: 'production'})).toThrow(/API_TOKEN/); - }); - - test('accepts API_TOKEN in production', () => { - const config = loadConfig({NODE_ENV: 'production', API_TOKEN: 'secret'}); - - expect(config.requiresApiToken).toBe(true); - expect(config.apiToken).toBe('secret'); - }); }); diff --git a/renderer/test/gacha-route.test.js b/renderer/test/gacha-route.test.js index 9ccafdb..57c5924 100644 --- a/renderer/test/gacha-route.test.js +++ b/renderer/test/gacha-route.test.js @@ -4,13 +4,11 @@ import {buildServer} from '../src/server.js'; /** @type {import('../src/config.js').AppConfig} */ const config = { - apiToken: undefined, host: '127.0.0.1', maxConcurrentRenders: 1, maxOptionChars: 40, maxOptions: 32, port: 0, - requiresApiToken: false, renderTimeoutMs: 15000, }; @@ -98,23 +96,6 @@ describe('POST /api/gacha', () => { await app.close(); }); - test('enforces bearer token when configured', async () => { - const app = await build({apiToken: 'secret'}); - - const denied = await app.inject({method: 'POST', url: '/api/gacha', payload: {label: 'Pizza', rarity: 3}}); - const allowed = await app.inject({ - method: 'POST', - url: '/api/gacha', - headers: {authorization: 'Bearer secret'}, - payload: {label: 'Pizza', rarity: 3}, - }); - - expect(denied.statusCode).toBe(401); - expect(allowed.statusCode).toBe(200); - - await app.close(); - }); - test('returns timeout response when rendering exceeds configured limit', async () => { const app = await build( {renderTimeoutMs: 7}, diff --git a/renderer/test/gif-route.test.js b/renderer/test/gif-route.test.js index c44248c..1228a5a 100644 --- a/renderer/test/gif-route.test.js +++ b/renderer/test/gif-route.test.js @@ -3,13 +3,11 @@ import {RenderTimeoutError} from '../src/lib/render-errors.js'; import {buildServer} from '../src/server.js'; const config = { - apiToken: undefined, host: '127.0.0.1', maxConcurrentRenders: 1, maxOptionChars: 40, maxOptions: 32, port: 0, - requiresApiToken: false, renderTimeoutMs: 15000, }; @@ -66,29 +64,6 @@ describe('POST /api/gif', () => { await app.close(); }); - test('enforces bearer token when configured', async () => { - const app = await buildServer({ - config: {...config, apiToken: 'secret'}, - renderGif: async () => ({ - buffer: Buffer.from('GIF89a-test'), - byteLength: 11, - durationMs: 12, - }), - }); - - const response = await app.inject({ - method: 'POST', - url: '/api/gif', - payload: { - options: ['a', 'b'], - }, - }); - - expect(response.statusCode).toBe(401); - - await app.close(); - }); - test('returns timeout response when rendering exceeds configured limit', async () => { const app = await buildServer({ config: {...config, renderTimeoutMs: 7},