diff --git a/apps/server/src/modules/workspaces/permission.ts b/apps/server/src/modules/workspaces/permission.ts index 2376d71c0b..02f988b581 100644 --- a/apps/server/src/modules/workspaces/permission.ts +++ b/apps/server/src/modules/workspaces/permission.ts @@ -47,37 +47,38 @@ export class PermissionService { async isAccessible(ws: string, id: string, user?: string): Promise { if (user) { - return await this.tryCheck(ws, user); + const hasPermission = await this.tryCheck(ws, user); + if (hasPermission) return true; + } + + // check if this is a public workspace + const count = await this.prisma.workspace.count({ + where: { id: ws, public: true }, + }); + if (count > 0) { + return true; + } + + // check whether this is a public subpage + const workspace = await this.prisma.userWorkspacePermission.findMany({ + where: { + workspaceId: ws, + userId: null, + }, + }); + const subpages = workspace + .map(ws => ws.subPageId) + .filter((v): v is string => !!v); + if (subpages.length > 0 && ws === id) { + // rootDoc is always accessible when there is a public subpage + return true; } else { - // check if this is a public workspace - const count = await this.prisma.workspace.count({ - where: { id: ws, public: true }, - }); - if (count > 0) { - return true; - } + // check if this is a public subpage - // check whether this is a public subpage - const workspace = await this.prisma.userWorkspacePermission.findMany({ - where: { - workspaceId: ws, - userId: null, - }, - }); - const subpages = workspace - .map(ws => ws.subPageId) - .filter((v): v is string => !!v); - if (subpages.length > 0 && ws === id) { - // rootDoc is always accessible when there is a public subpage - return true; - } else { - // check if this is a public subpage - - // why use `endsWith`? - // because there might have `${wsId}:space:${subpageId}`, - // but subpages only have `${subpageId}` - return subpages.some(subpage => id.endsWith(subpage)); - } + // why use `endsWith`? + // because there might have `${wsId}:space:${subpageId}`, + // but subpages only have `${subpageId}` + return subpages.some(subpage => id.endsWith(subpage)); } } diff --git a/apps/server/tests/workspace.e2e.ts b/apps/server/tests/workspace.e2e.ts index 1249d8dd8b..d569eff473 100644 --- a/apps/server/tests/workspace.e2e.ts +++ b/apps/server/tests/workspace.e2e.ts @@ -132,6 +132,26 @@ test('should share a page', async t => { t.is(pages.length, 1, 'failed to get shared pages'); t.is(pages[0], 'page1', 'failed to get shared page: page1'); + const resp1 = await request(app.getHttpServer()) + .get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`) + .auth(u1.token.token, { type: 'bearer' }); + t.is(resp1.statusCode, 200, 'failed to get root doc with u1 token'); + const resp2 = await request(app.getHttpServer()).get( + `/api/workspaces/${workspace.id}/docs/${workspace.id}` + ); + t.is(resp2.statusCode, 200, 'should not get root doc without token'); + + const resp3 = await request(app.getHttpServer()) + .get(`/api/workspaces/${workspace.id}/docs/page1`) + .auth(u1.token.token, { type: 'bearer' }); + // 404 because we don't put the page doc to server + t.is(resp3.statusCode, 404, 'failed to get shared doc with u1 token'); + const resp4 = await request(app.getHttpServer()).get( + `/api/workspaces/${workspace.id}/docs/page1` + ); + // 404 because we don't put the page doc to server + t.is(resp4.statusCode, 404, 'should not get shared doc without token'); + const msg1 = await sharePage(app, u2.token.token, 'not_exists_ws', 'page2'); t.is(msg1, 'Permission denied', 'unauthorized user can share page'); const msg2 = await revokePage(app, u2.token.token, 'not_exists_ws', 'page2');