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:
parent
d335670b91
commit
22ba4d0f48
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
Reference in New Issue