mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
fix(api): 🔒 Correctly check for note ownership when editing
This commit is contained in:
parent
653cf712ea
commit
9682cd0f99
|
|
@ -73,7 +73,7 @@ export default apiRoute((app) =>
|
|||
|
||||
const note = await Note.fromId(id, user?.id);
|
||||
|
||||
if (!note?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@ export default apiRoute((app) =>
|
|||
return context.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const status = await Note.fromId(id, user?.id);
|
||||
const note = await Note.fromId(id, user?.id);
|
||||
|
||||
if (!status?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ export default apiRoute((app) =>
|
|||
max_id ? lt(Users.id, max_id) : undefined,
|
||||
since_id ? gte(Users.id, since_id) : undefined,
|
||||
min_id ? gt(Users.id, min_id) : undefined,
|
||||
sql`EXISTS (SELECT 1 FROM "Likes" WHERE "Likes"."likedId" = ${status.id} AND "Likes"."likerId" = ${Users.id})`,
|
||||
sql`EXISTS (SELECT 1 FROM "Likes" WHERE "Likes"."likedId" = ${note.id} AND "Likes"."likerId" = ${Users.id})`,
|
||||
),
|
||||
limit,
|
||||
context.req.url,
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ export default apiRoute((app) => {
|
|||
|
||||
const note = await Note.fromId(id, user?.id);
|
||||
|
||||
if (!note?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +228,7 @@ export default apiRoute((app) => {
|
|||
|
||||
const note = await Note.fromId(id, user?.id);
|
||||
|
||||
if (!note?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ export default apiRoute((app) => {
|
|||
|
||||
const note = await Note.fromId(id, user?.id);
|
||||
|
||||
if (!note?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,17 +104,14 @@ export default apiRoute((app) =>
|
|||
return context.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const foundStatus = await Note.fromId(id, user.id);
|
||||
const note = await Note.fromId(id, user.id);
|
||||
|
||||
if (!foundStatus?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
const existingReblog = await Note.fromSql(
|
||||
and(
|
||||
eq(Notes.authorId, user.id),
|
||||
eq(Notes.reblogId, foundStatus.data.id),
|
||||
),
|
||||
and(eq(Notes.authorId, user.id), eq(Notes.reblogId, note.data.id)),
|
||||
);
|
||||
|
||||
if (existingReblog) {
|
||||
|
|
@ -123,7 +120,7 @@ export default apiRoute((app) =>
|
|||
|
||||
const newReblog = await Note.insert({
|
||||
authorId: user.id,
|
||||
reblogId: foundStatus.data.id,
|
||||
reblogId: note.data.id,
|
||||
visibility,
|
||||
sensitive: false,
|
||||
updatedAt: new Date().toISOString(),
|
||||
|
|
@ -140,10 +137,10 @@ export default apiRoute((app) =>
|
|||
return context.json({ error: "Failed to reblog" }, 500);
|
||||
}
|
||||
|
||||
if (foundStatus.author.isLocal() && user.isLocal()) {
|
||||
if (note.author.isLocal() && user.isLocal()) {
|
||||
await Notification.insert({
|
||||
accountId: user.id,
|
||||
notifiedId: foundStatus.author.id,
|
||||
notifiedId: note.author.id,
|
||||
type: "reblog",
|
||||
noteId: newReblog.data.reblogId,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ export default apiRoute((app) =>
|
|||
return context.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const status = await Note.fromId(id, user.id);
|
||||
const note = await Note.fromId(id, user.id);
|
||||
|
||||
if (!status?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ export default apiRoute((app) =>
|
|||
max_id ? lt(Users.id, max_id) : undefined,
|
||||
since_id ? gte(Users.id, since_id) : undefined,
|
||||
min_id ? gt(Users.id, min_id) : undefined,
|
||||
sql`EXISTS (SELECT 1 FROM "Notes" WHERE "Notes"."reblogId" = ${status.id} AND "Notes"."authorId" = ${Users.id})`,
|
||||
sql`EXISTS (SELECT 1 FROM "Notes" WHERE "Notes"."reblogId" = ${note.id} AND "Notes"."authorId" = ${Users.id})`,
|
||||
),
|
||||
limit,
|
||||
context.req.url,
|
||||
|
|
|
|||
|
|
@ -75,18 +75,18 @@ export default apiRoute((app) =>
|
|||
return context.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const status = await Note.fromId(id, user.id);
|
||||
const note = await Note.fromId(id, user.id);
|
||||
|
||||
if (!status?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
return context.json(
|
||||
{
|
||||
id: status.id,
|
||||
id: note.id,
|
||||
// TODO: Give real source for spoilerText
|
||||
spoiler_text: status.data.spoilerText,
|
||||
text: status.data.contentSource,
|
||||
spoiler_text: note.data.spoilerText,
|
||||
text: note.data.contentSource,
|
||||
} satisfies ApiStatusSource,
|
||||
200,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export default apiRoute((app) =>
|
|||
|
||||
const note = await Note.fromId(id, user.id);
|
||||
|
||||
if (!note?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,18 +79,15 @@ export default apiRoute((app) =>
|
|||
return context.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const foundStatus = await Note.fromId(id, user.id);
|
||||
const note = await Note.fromId(id, user.id);
|
||||
|
||||
// Check if user is authorized to view this status (if it's private)
|
||||
if (!foundStatus?.isViewableByUser(user)) {
|
||||
if (!(note && (await note?.isViewableByUser(user)))) {
|
||||
return context.json({ error: "Record not found" }, 404);
|
||||
}
|
||||
|
||||
const existingReblog = await Note.fromSql(
|
||||
and(
|
||||
eq(Notes.authorId, user.id),
|
||||
eq(Notes.reblogId, foundStatus.data.id),
|
||||
),
|
||||
and(eq(Notes.authorId, user.id), eq(Notes.reblogId, note.data.id)),
|
||||
undefined,
|
||||
user?.id,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ export default apiRoute((app) =>
|
|||
foundAuthor = foundObject ? foundObject.author : null;
|
||||
|
||||
if (foundObject) {
|
||||
if (!foundObject.isViewableByUser(null)) {
|
||||
if (!(await foundObject.isViewableByUser(null))) {
|
||||
return context.json({ error: "Object not found" }, 404);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1099,8 +1099,13 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
|
|||
}
|
||||
|
||||
// Filter for posts that are viewable by the user
|
||||
const viewableAncestors = ancestors.filter((ancestor) =>
|
||||
ancestor.isViewableByUser(fetcher),
|
||||
const viewableAncestors = await Promise.all(
|
||||
ancestors.map(async (ancestor) => {
|
||||
const isViewable = await ancestor.isViewableByUser(fetcher);
|
||||
return isViewable ? ancestor : null;
|
||||
}),
|
||||
).then((filteredAncestors) =>
|
||||
filteredAncestors.filter((n) => n !== null),
|
||||
);
|
||||
|
||||
// Reverse the order so that the oldest posts are first
|
||||
|
|
@ -1133,8 +1138,13 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
|
|||
|
||||
// Filter for posts that are viewable by the user
|
||||
|
||||
const viewableDescendants = descendants.filter((descendant) =>
|
||||
descendant.isViewableByUser(fetcher),
|
||||
const viewableDescendants = await Promise.all(
|
||||
descendants.map(async (descendant) => {
|
||||
const isViewable = await descendant.isViewableByUser(fetcher);
|
||||
return isViewable ? descendant : null;
|
||||
}),
|
||||
).then((filteredDescendants) =>
|
||||
filteredDescendants.filter((n) => n !== null),
|
||||
);
|
||||
|
||||
return viewableDescendants;
|
||||
|
|
|
|||
Loading…
Reference in a new issue