diff --git a/packages/backend/server/src/__tests__/e2e/doc/resolver.spec.ts b/packages/backend/server/src/__tests__/e2e/doc/resolver.spec.ts index 93ddb70685..192980f938 100644 --- a/packages/backend/server/src/__tests__/e2e/doc/resolver.spec.ts +++ b/packages/backend/server/src/__tests__/e2e/doc/resolver.spec.ts @@ -306,3 +306,50 @@ e2e('should require Doc.Read to query workspace page meta', async t => { }) ); }); + +e2e('should require Doc.Read to query doc histories', async t => { + const owner = await app.signup(); + const member = await app.createUser(); + await app.login(member); + + await app.switchUser(owner); + const workspace = await app.create(Mockers.Workspace, { + owner: { id: owner.id }, + }); + await app.create(Mockers.WorkspaceUser, { + workspaceId: workspace.id, + userId: member.id, + type: WorkspaceRole.Collaborator, + }); + + const docSnapshot = await app.create(Mockers.DocSnapshot, { + workspaceId: workspace.id, + user: owner, + }); + const doc = await app.create(Mockers.DocMeta, { + workspaceId: workspace.id, + docId: docSnapshot.id, + title: 'private-doc', + defaultRole: DocRole.None, + }); + + await app.switchUser(member); + await t.throwsAsync( + app.gql({ + query: { + id: 'workspaceDocHistoriesPermissionCheck', + op: 'workspaceDocHistoriesPermissionCheck', + query: ` + query { + workspace(id: "${workspace.id}") { + histories(guid: "${doc.docId}") { + timestamp + } + } + } + `, + } satisfies GraphQLQuery, + variables: undefined, + }) + ); +}); diff --git a/packages/backend/server/src/core/workspaces/resolvers/history.ts b/packages/backend/server/src/core/workspaces/resolvers/history.ts index b87dee5686..88b6962096 100644 --- a/packages/backend/server/src/core/workspaces/resolvers/history.ts +++ b/packages/backend/server/src/core/workspaces/resolvers/history.ts @@ -42,6 +42,7 @@ export class DocHistoryResolver { @ResolveField(() => [DocHistoryType]) async histories( + @CurrentUser() user: CurrentUser, @Parent() workspace: WorkspaceType, @Args('guid') guid: string, @Args({ name: 'before', type: () => GraphQLISODateTime, nullable: true }) @@ -51,6 +52,8 @@ export class DocHistoryResolver { ): Promise { const docId = new DocID(guid, workspace.id); + await this.ac.user(user.id).doc(docId).assert('Doc.Read'); + const histories = await this.workspace.listDocHistories( workspace.id, docId.guid,