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:
@ -585,6 +585,7 @@ async function loadDocument({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (document.deletedAt) {
|
if (document.deletedAt) {
|
||||||
|
// don't send data if user cannot restore deleted doc
|
||||||
authorize(user, "restore", document);
|
authorize(user, "restore", document);
|
||||||
} else {
|
} else {
|
||||||
authorize(user, "read", document);
|
authorize(user, "read", document);
|
||||||
|
@ -98,6 +98,74 @@ describe("#documents.info", () => {
|
|||||||
expect(share.lastAccessedAt).toBeTruthy();
|
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", () => {
|
describe("apiVersion=2", () => {
|
||||||
it("should return sharedTree from shareId", async () => {
|
it("should return sharedTree from shareId", async () => {
|
||||||
const { document, collection, user } = await seed();
|
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) {
|
if (userId) {
|
||||||
return {
|
return {
|
||||||
include: [
|
include: [
|
||||||
@ -172,6 +172,7 @@ Document.associate = (models) => {
|
|||||||
method: ["withMembership", userId],
|
method: ["withMembership", userId],
|
||||||
}),
|
}),
|
||||||
as: "collection",
|
as: "collection",
|
||||||
|
paranoid,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -221,7 +222,7 @@ Document.findByPk = async function (id, options = {}) {
|
|||||||
const scope = this.scope(
|
const scope = this.scope(
|
||||||
"withUnpublished",
|
"withUnpublished",
|
||||||
{
|
{
|
||||||
method: ["withCollection", options.userId],
|
method: ["withCollection", options.userId, options.paranoid],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
method: ["withViews", options.userId],
|
method: ["withViews", options.userId],
|
||||||
|
@ -135,6 +135,11 @@ allow(User, "permanentDelete", Document, (user, document) => {
|
|||||||
allow(User, "restore", Document, (user, document) => {
|
allow(User, "restore", Document, (user, document) => {
|
||||||
if (user.isViewer) return false;
|
if (user.isViewer) return false;
|
||||||
if (!document.deletedAt) return false;
|
if (!document.deletedAt) return false;
|
||||||
|
|
||||||
|
if (document.collection && cannot(user, "update", document.collection)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return user.teamId === document.teamId;
|
return user.teamId === document.teamId;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user