Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions packages/wabe-mongodb/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,40 @@ describe('Mongo adapter', () => {
expect(res2.length).toBe(1)
})

it('should correctly exclude documents with notContains on array of objects (ACL notContains fix)', async () => {
await mongoAdapter.createObject({
className: 'Test',
data: {
object: { array: [{ string: 'user1' }] },
},
context,
})

await mongoAdapter.createObject({
className: 'Test',
data: {
object: { array: [{ string: 'user2' }] },
},
context,
})

const res = await mongoAdapter.getObjects({
className: 'Test',
context,
where: {
object: {
// @ts-expect-error
array: {
notContains: { string: 'user1' },
},
},
},
})

expect(res.length).toBe(1)
expect(res[0]?.object?.array).toEqual([{ string: 'user2' }])
})

it('should retry on connection error', async () => {
const spyMongoClientConnect = spyOn(mongoAdapter.client, 'connect').mockImplementationOnce(
() => {
Expand Down
5 changes: 4 additions & 1 deletion packages/wabe-mongodb/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ export const buildMongoWhereQuery = <T extends WabeTypes, K extends keyof T['typ
$all: Array.isArray(value.contains) ? value.contains : [value.contains],
}
if (value?.notContains || value?.notContains === null)
acc[keyToWrite] = { $ne: value.notContains }
acc[keyToWrite] =
typeof value.notContains === 'object' && !Array.isArray(value.notContains)
? { $not: { $elemMatch: value.notContains } }
: { $nin: Array.isArray(value.notContains) ? value.notContains : [value.notContains] }
if (value?.exists === true) acc[keyToWrite] = { $exists: true, $ne: null }
if (value?.exists === false) acc[keyToWrite] = { $eq: null }

Expand Down
34 changes: 34 additions & 0 deletions packages/wabe-postgres/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,40 @@ describe('Postgres adapter', () => {
expect(res2.length).toBe(1)
})

it('should correctly exclude documents with notContains on array of objects (ACL notContains fix)', async () => {
await postgresAdapter.createObject({
className: 'Test',
data: {
object: { array: [{ string: 'user1' }] },
},
context,
})

await postgresAdapter.createObject({
className: 'Test',
data: {
object: { array: [{ string: 'user2' }] },
},
context,
})

const res = await postgresAdapter.getObjects({
className: 'Test',
context,
where: {
object: {
// @ts-expect-error
array: {
notContains: { string: 'user1' },
},
},
},
})

expect(res.length).toBe(1)
expect(res[0]?.object?.array).toEqual([{ string: 'user2' }])
})

it('should create class', async () => {
const client = await postgresAdapter.pool.connect()

Expand Down
112 changes: 112 additions & 0 deletions packages/wabe/src/security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1902,6 +1902,118 @@ describe('Security tests', () => {
await closeTests(wabe)
})

it('should not authorize an user to read an object when explicitly denied in acl.users even if role has access (MongoDB notContains)', async () => {
const setup = await setupTests([
{
name: 'TestNotContains',
fields: {
name: { type: 'String' },
},
permissions: {
read: {
authorizedRoles: ['Client'],
requireAuthentication: true,
},
create: {
authorizedRoles: ['Client'],
requireAuthentication: true,
},
},
},
])
const wabe = setup.wabe
const port = setup.port
const client = getAnonymousClient(port)
const rootClient = getGraphqlClient(port)

const { userClient, userId } = await createUserAndUpdateRole({
anonymousClient: client,
port,
roleName: 'Client',
rootClient,
})

const clientRole = await rootClient.request<any>(gql`
query getClientRole {
roles(where: { name: { equalTo: "Client" } }) {
edges {
node {
id
}
}
}
}
`)

const clientRoleId = clientRole.roles.edges[0].node.id

const objectCreated = await rootClient.request<any>(gql`
mutation createTestNotContains {
createTestNotContains(input: { fields: { name: "secret" } }) {
testNotContains {
id
}
}
}
`)

const objectId = objectCreated.createTestNotContains.testNotContains.id

await rootClient.request<any>(gql`
mutation updateACL {
updateTestNotContains(input: {
id: "${objectId}",
fields: {
acl: {
users: [{
userId: "${userId}",
read: false,
write: false
}],
roles: [{
roleId: "${clientRoleId}",
read: true,
write: true
}]
}
}
}) {
testNotContains {
id
}
}
}
`)

await expect(
userClient.request<any>(gql`
query testNotContains {
testNotContains(id: "${objectId}") {
id
name
}
}
`),
).rejects.toThrow('Object not found')

const resList = await userClient.request<any>(gql`
query testNotContainses {
testNotContainses {
edges {
node {
id
name
}
}
}
}
`)

expect(resList.testNotContainses.edges.length).toEqual(0)

await closeTests(wabe)
})

it('should not authorize an user to write (delete) an object when the user has not access on write to the object (ACL)', async () => {
const setup = await setupTests([
{
Expand Down