From f4dfbd735b6778dd2782d16bb765d42f990d7c2c Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 11 Aug 2026 18:03:15 -0700 Subject: [PATCH] fix: resolve 'app-'-prefixed app names in feedback target lookup APP_NAME_REGEX allows names beginning with "app-" (e.g. the seeded app-center), but resolveTargetApp's startsWith('app-') heuristic sent those to a uid-only lookup with no name fallback, so feedback for such apps 403'd even when enabled. Use AppStore.resolveApp (uid, then name) like the rest of the codebase. --- .../feedback/AppFeedbackController.test.ts | 23 +++++++++++++++++-- .../services/feedback/AppFeedbackService.ts | 6 ++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/backend/controllers/feedback/AppFeedbackController.test.ts b/src/backend/controllers/feedback/AppFeedbackController.test.ts index 3e9d15872..e9701980b 100644 --- a/src/backend/controllers/feedback/AppFeedbackController.test.ts +++ b/src/backend/controllers/feedback/AppFeedbackController.test.ts @@ -84,9 +84,10 @@ const makeUser = async (): Promise<{ actor: Actor; userId: number }> => { const makeApp = async ( ownerUserId: number, - opts: { feedbackEnabled?: boolean; indexUrl?: string } = {}, + opts: { feedbackEnabled?: boolean; indexUrl?: string; name?: string } = {}, ) => { - const name = `fdbk-app-${Math.random().toString(36).slice(2, 10)}`; + const name = + opts.name ?? `fdbk-app-${Math.random().toString(36).slice(2, 10)}`; return await server.stores.app.create( { name, @@ -251,6 +252,24 @@ describe('AppFeedbackController GET /target', () => { }); }); + it('resolves an opted-in app whose name starts with "app-"', async () => { + const { userId: ownerId } = await makeUser(); + const name = `app-fdbk-${Math.random().toString(36).slice(2, 10)}`; + const app = await makeApp(ownerId, { feedbackEnabled: true, name }); + const { actor } = await makeUser(); + const { res, captured } = makeRes(); + await callRoute( + 'get', + '/target', + makeReq({ query: { app: name }, actor }), + res, + ); + expect(captured.body).toEqual({ + enabled: true, + app: { name: app.name, title: app.title }, + }); + }); + it('resolves an origin to the app whose index_url it matches', async () => { const { userId: ownerId } = await makeUser(); const app = await makeApp(ownerId, { feedbackEnabled: true }); diff --git a/src/backend/services/feedback/AppFeedbackService.ts b/src/backend/services/feedback/AppFeedbackService.ts index c79698fa7..7c129a5c9 100644 --- a/src/backend/services/feedback/AppFeedbackService.ts +++ b/src/backend/services/feedback/AppFeedbackService.ts @@ -92,9 +92,9 @@ export class AppFeedbackService extends PuterService { origin?: string; }): Promise | null> { if (app) { - return app.startsWith('app-') - ? await this.stores.app.getByUid(app) - : await this.stores.app.getByName(app); + // Names may legally start with "app-" (e.g. "app-center"), so a + // prefix heuristic would misroute them; try uid first, then name. + return await this.stores.app.resolveApp(app); } if (origin) { let uid;