fix: Improve validation of edge cases with documents.move endpoint. closes #6015

This commit is contained in:
Tom Moor
2023-10-16 21:04:13 -04:00
parent a357cbaf8d
commit 0bec781695
2 changed files with 61 additions and 2 deletions

View File

@@ -38,6 +38,7 @@ import getTasks from "@shared/utils/getTasks";
import slugify from "@shared/utils/slugify";
import { SLUG_URL_REGEX } from "@shared/utils/urlHelpers";
import { DocumentValidation } from "@shared/validations";
import { ValidationError } from "@server/errors";
import Backlink from "./Backlink";
import Collection from "./Collection";
import FileOperation from "./FileOperation";
@@ -354,6 +355,7 @@ class Document extends ParanoidModel {
model.collaboratorIds = [];
}
// ensure the last modifying user is a collaborator
model.collaboratorIds = uniq(
model.collaboratorIds.concat(model.lastModifiedById)
);
@@ -362,6 +364,32 @@ class Document extends ParanoidModel {
model.revisionCount += 1;
}
@BeforeUpdate
static async checkParentDocument(model: Document, options: SaveOptions) {
if (
model.previous("parentDocumentId") === model.parentDocumentId ||
!model.parentDocumentId
) {
return;
}
if (model.parentDocumentId === model.id) {
throw ValidationError(
"infinite loop detected, cannot nest a document inside itself"
);
}
const childDocumentIds = await model.findAllChildDocumentIds(
undefined,
options
);
if (childDocumentIds.includes(model.parentDocumentId)) {
throw ValidationError(
"infinite loop detected, cannot nest a document inside itself"
);
}
}
// associations
@BelongsTo(() => FileOperation, "importId")

View File

@@ -2004,11 +2004,10 @@ describe("#documents.move", () => {
userId: user.id,
teamId: user.teamId,
});
const collection = await buildCollection();
const res = await server.post("/api/documents.move", {
body: {
id: document.id,
collectionId: collection.id,
collectionId: document.collectionId,
parentDocumentId: document.id,
token: user.getJwtToken(),
},
@@ -2020,6 +2019,38 @@ describe("#documents.move", () => {
);
});
it("should fail if attempting to nest doc within a child of itself", async () => {
const user = await buildUser();
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
collectionId: collection.id,
});
const childDocument = await buildDocument({
userId: user.id,
teamId: user.teamId,
collectionId: document.collectionId,
parentDocumentId: document.id,
});
const res = await server.post("/api/documents.move", {
body: {
id: document.id,
collectionId: document.collectionId,
parentDocumentId: childDocument.id,
token: user.getJwtToken(),
},
});
const body = await res.json();
expect(res.status).toEqual(400);
expect(body.message).toEqual(
"infinite loop detected, cannot nest a document inside itself"
);
});
it("should fail if attempting to nest doc within a draft", async () => {
const user = await buildUser();
const collection = await buildCollection({