fix: prevent access to docs in trash from deleted private collections (#2431)

* Check for collection in deleted document

* Add tests

* Use update policy

* Set paranoid to false when fetching deleted doc

* Update policy
This commit is contained in:
Saumya Pandey 2021-08-26 09:35:59 +05:30 committed by GitHub
parent d335670b91
commit 22ba4d0f48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 2 deletions

View File

@ -585,6 +585,7 @@ async function loadDocument({
}
if (document.deletedAt) {
// don't send data if user cannot restore deleted doc
authorize(user, "restore", document);
} else {
authorize(user, "read", document);

View File

@ -98,6 +98,74 @@ describe("#documents.info", () => {
expect(share.lastAccessedAt).toBeTruthy();
});
it("should not return document of a deleted collection, when the user was absent in the collection", async () => {
const user = await buildUser();
const user2 = await buildUser({
teamId: user.teamId,
});
const collection = await buildCollection({
permission: null,
teamId: user.teamId,
createdById: user.id,
});
const doc = await buildDocument({
collectionId: collection.id,
teamId: user.teamId,
userId: user.id,
});
await server.post("/api/collections.delete", {
body: {
id: collection.id,
token: user.getJwtToken(),
},
});
const res = await server.post("/api/documents.info", {
body: {
id: doc.id,
token: user2.getJwtToken(),
},
});
expect(res.status).toEqual(403);
});
it("should return document of a deleted collection, when the user was present in the collection", async () => {
const user = await buildUser();
const collection = await buildCollection({
permission: null,
teamId: user.teamId,
createdById: user.id,
});
const doc = await buildDocument({
collectionId: collection.id,
teamId: user.teamId,
userId: user.id,
});
await server.post("/api/collections.delete", {
body: {
id: collection.id,
token: user.getJwtToken(),
},
});
const res = await server.post("/api/documents.info", {
body: {
id: doc.id,
token: user.getJwtToken(),
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.id).toEqual(doc.id);
});
describe("apiVersion=2", () => {
it("should return sharedTree from shareId", async () => {
const { document, collection, user } = await seed();

View File

@ -163,7 +163,7 @@ Document.associate = (models) => {
},
},
});
Document.addScope("withCollection", (userId) => {
Document.addScope("withCollection", (userId, paranoid = true) => {
if (userId) {
return {
include: [
@ -172,6 +172,7 @@ Document.associate = (models) => {
method: ["withMembership", userId],
}),
as: "collection",
paranoid,
},
],
};
@ -221,7 +222,7 @@ Document.findByPk = async function (id, options = {}) {
const scope = this.scope(
"withUnpublished",
{
method: ["withCollection", options.userId],
method: ["withCollection", options.userId, options.paranoid],
},
{
method: ["withViews", options.userId],

View File

@ -135,6 +135,11 @@ allow(User, "permanentDelete", Document, (user, document) => {
allow(User, "restore", Document, (user, document) => {
if (user.isViewer) return false;
if (!document.deletedAt) return false;
if (document.collection && cannot(user, "update", document.collection)) {
return false;
}
return user.teamId === document.teamId;
});