Files
Daniel Gak Anagrov 55f91d2cdf fix(gql): scopes, roles, auth (#5724)
* fix(workspace): auto approval
* fix(scopes): access scopes across the server
* fix(hasAccessRole): establish for all mutations
* feat(token): scoping does not require the token to exist
* chore(scopes): added additional roles
* fix: replaced UNAUTHORIZED_ACCESS_ERROR with UNAUTHORIZED
* fix(email): user list scopes
2025-10-29 09:53:11 +00:00

356 lines
11 KiB
TypeScript

import { createRandomString } from '@/modules/core/helpers/testHelpers'
import type { BasicTestWorkspace } from '@/modules/workspaces/tests/helpers/creation'
import { createTestWorkspace } from '@/modules/workspaces/tests/helpers/creation'
import type { BasicTestUser } from '@/test/authHelper'
import { createTestUser, login } from '@/test/authHelper'
import {
ApproveJoinRequestDocument,
DenyJoinRequestDocument,
DismissWorkspaceDocument,
GetActiveUserWithWorkspaceJoinRequestsDocument,
GetWorkspaceTeamDocument,
GetWorkspaceWithJoinRequestsDocument,
RequestToJoinWorkspaceDocument
} from '@/modules/core/graph/generated/graphql'
import { beforeEachContext } from '@/test/hooks'
import { Roles } from '@speckle/shared'
import { expect } from 'chai'
describe('WorkspaceJoinRequests GQL', () => {
let admin: BasicTestUser
let user1: BasicTestUser
let user2: BasicTestUser
let user3: BasicTestUser
let workspace1: BasicTestWorkspace
let workspace2: BasicTestWorkspace
let dismissedWorkspace: BasicTestWorkspace
let workspaceAutoJoin: BasicTestWorkspace
before(async () => {
await beforeEachContext()
;[admin, user1, user2, user3] = await Promise.all([
createTestUser({
name: 'admin user',
role: Roles.Server.User,
email: `${createRandomString()}@example.org`,
verified: true
}),
createTestUser({
name: 'user 1',
role: Roles.Server.User,
email: `${createRandomString()}@example.org`,
verified: true
}),
createTestUser({
name: 'user 2',
role: Roles.Server.User,
email: `${createRandomString()}@example.org`,
verified: true
}),
createTestUser({
name: 'user 3',
role: Roles.Server.User,
email: `${createRandomString()}@example.org`,
verified: true
})
])
;[workspace1, dismissedWorkspace, workspace2, workspaceAutoJoin] =
await Promise.all([
await createTestWorkspace(
{
id: createRandomString(),
name: 'Workspace 1',
ownerId: admin.id,
description: '',
discoverabilityEnabled: true
},
admin,
{ domain: 'example.org' }
),
await createTestWorkspace(
{
id: createRandomString(),
name: 'should not be visible',
ownerId: admin.id,
description: '',
discoverabilityEnabled: true
},
admin,
{
domain: 'example.org'
}
),
await createTestWorkspace(
{
id: createRandomString(),
name: 'Workspace 2',
ownerId: admin.id,
description: '',
discoverabilityEnabled: true
},
admin,
{ domain: 'example.org' }
),
await createTestWorkspace(
{
id: createRandomString(),
name: 'Worksapce autojoin',
ownerId: admin.id,
description: '',
discoverabilityEnabled: true,
discoverabilityAutoJoinEnabled: true
},
admin,
{
domain: 'example.org'
}
)
])
})
describe('Workspace.adminWorkspacesJoinRequests', () => {
it('allows users to request joining a workspace', async () => {
// User1 requests to join workspace1
const sessionUser1 = await login(user1)
await sessionUser1.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: workspace1.id } },
{ assertNoErrors: true }
)
// admin logs in
const sessionAdmin = await login(admin)
const workspace1Res = await sessionAdmin.execute(
GetWorkspaceWithJoinRequestsDocument,
{ workspaceId: workspace1.id },
{ assertNoErrors: true }
)
// has one join request
const { items: items, totalCount: totalCount } =
workspace1Res.data!.workspace!.adminWorkspacesJoinRequests!
expect(totalCount).to.equal(1)
expect(items).to.have.length(1)
expect(items[0].status).to.equal('pending')
expect(items[0].workspace.id).to.equal(workspace1.id)
expect(items[0].user.id).to.equal(user1.id)
})
it('has the ability to dismiss a join request', async () => {
// User2 requests to join dismissedWorkspace
const sessionUser2 = await login(user2)
await sessionUser2.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: dismissedWorkspace.id } },
{ assertNoErrors: true }
)
// admins sees a request
const sessionAdmin = await login(admin)
const joinRequests = await sessionAdmin.execute(
GetWorkspaceWithJoinRequestsDocument,
{ workspaceId: dismissedWorkspace.id },
{ assertNoErrors: true }
)
const { workspace: joinsWorkspace2 } = joinRequests.data!
expect(joinsWorkspace2!.adminWorkspacesJoinRequests!.totalCount).to.equal(1)
// user2 cancels the request
await sessionUser2.execute(
DismissWorkspaceDocument,
{ input: { workspaceId: dismissedWorkspace.id } },
{ assertNoErrors: true }
)
// no request for admin
const workspaceDismissedRes = await sessionAdmin.execute(
GetWorkspaceWithJoinRequestsDocument,
{ workspaceId: dismissedWorkspace.id },
{ assertNoErrors: true }
)
const { workspace } = workspaceDismissedRes.data!
expect(workspace.adminWorkspacesJoinRequests!.items).to.have.lengthOf(0)
expect(workspace.adminWorkspacesJoinRequests!.totalCount).to.eql(0)
})
})
describe('User.workspaceJoinRequests', () => {
it('should return the workspace join requests for the user', async () => {
// User requests to join workspace1 and 2
const sessionUser = await login(user1)
await sessionUser.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: workspace1.id } },
{ assertNoErrors: true }
)
await sessionUser.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: workspace2.id } },
{ assertNoErrors: true }
)
const res = await sessionUser.execute(
GetActiveUserWithWorkspaceJoinRequestsDocument,
{},
{ assertNoErrors: true }
)
const { items, totalCount } = res.data!.activeUser!.workspaceJoinRequests!
expect(totalCount).to.equal(2)
expect(items).to.have.length(2)
expect(items[0].status).to.equal('pending')
expect(items[0].workspace.id).to.equal(workspace2.id)
expect(items[0].user.id).to.equal(user1.id)
expect(items[1].status).to.equal('pending')
expect(items[1].workspace.id).to.equal(workspace1.id)
expect(items[1].user.id).to.equal(user1.id)
})
it('does not show request that were dissmissed for the user', async () => {
// User requests to join workspaceDismissed
const sessionUser = await login(user2)
await sessionUser.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: dismissedWorkspace.id } },
{ assertNoErrors: true }
)
// dismisses it
await sessionUser.execute(
DismissWorkspaceDocument,
{ input: { workspaceId: dismissedWorkspace.id } },
{ assertNoErrors: true }
)
const res = await sessionUser.execute(
GetActiveUserWithWorkspaceJoinRequestsDocument,
{},
{ assertNoErrors: true }
)
const { items, totalCount } = res.data!.activeUser!.workspaceJoinRequests!
expect(totalCount).to.equal(0)
expect(items).to.have.length(0)
})
})
describe('joining a workspace', () => {
it('allows admin accepting a join request to a workspace', async () => {
const sessionAdmin = await login(admin)
const sessionUser = await login(user1)
// User requests to join workspace1
await sessionUser.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: workspace1.id } },
{ assertNoErrors: true }
)
await sessionAdmin.execute(
ApproveJoinRequestDocument,
{ input: { workspaceId: workspace1.id, userId: user1.id } },
{ assertNoErrors: true }
)
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace1.id
})
const { items, totalCount } = res.data!.workspace.team
expect(totalCount).to.equal(2)
expect(items).to.have.length(2)
expect(items[0].id).to.equal(user1.id)
})
it('allows admin denying a join request to a workspace', async () => {
const sessionAdmin = await login(admin)
const sessionUser = await login(user2)
// User requests to join workspace1
await sessionUser.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: workspace2.id } },
{ assertNoErrors: true }
)
await sessionAdmin.execute(
DenyJoinRequestDocument,
{ input: { workspaceId: workspace2.id, userId: user2.id } },
{ assertNoErrors: true }
)
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace2.id
})
const { items, totalCount } = res.data!.workspace.team
expect(totalCount).to.equal(1)
expect(items).to.have.length(1)
})
it('doesnt allow the joiner user to hack around their way into a workspace', async () => {
const sessionAdmin = await login(admin)
const sessionUser = await login(user3)
// User requests to join workspace1
await sessionUser.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: workspace2.id } },
{ assertNoErrors: true }
)
// Accepts himself
const autoAcceptAttempt = await sessionUser.execute(
ApproveJoinRequestDocument,
{ input: { workspaceId: workspace2.id, userId: user3.id } },
{ assertNoErrors: false }
)
const autoDenyAttempt = await sessionUser.execute(
DenyJoinRequestDocument,
{ input: { workspaceId: workspace2.id, userId: user3.id } },
{ assertNoErrors: false }
)
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace2.id
})
const { items, totalCount } = res.data!.workspace.team
const AUTH_ERROR = 'You are not authorized to access this resource.'
expect(autoAcceptAttempt).to.haveGraphQLErrors()
expect(autoAcceptAttempt.errors![0].message).to.contain(AUTH_ERROR)
expect(autoDenyAttempt).to.haveGraphQLErrors()
expect(autoDenyAttempt.errors![0].message).to.contain(AUTH_ERROR)
expect(totalCount).to.equal(1)
expect(items).to.have.length(1)
})
it('can auto join if admin had previously preconfigured it', async () => {
const sessionAdmin = await login(admin)
const sessionUser = await login(user3)
// User requests to join workspace1
await sessionUser.execute(
RequestToJoinWorkspaceDocument,
{ input: { workspaceId: workspaceAutoJoin.id } },
{ assertNoErrors: true }
)
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
workspaceId: workspaceAutoJoin.id
})
const { items, totalCount } = res.data!.workspace.team
expect(totalCount).to.equal(2)
expect(items).to.have.length(2)
expect(items[0].id).to.equal(user3.id)
})
})
})