From d0c8a37fe5db62d80be317aefdf7437bf3891cf9 Mon Sep 17 00:00:00 2001 From: Jared Pereira Date: Wed, 3 Dec 2025 14:01:56 -0500 Subject: [PATCH] don't allow users to delete drafts they don't own --- actions/deleteLeaflet.ts | 46 +++++++++++++++++++ .../home/LeafletList/LeafletOptions.tsx | 20 +++++--- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/actions/deleteLeaflet.ts b/actions/deleteLeaflet.ts index 55534656..d6108def 100644 --- a/actions/deleteLeaflet.ts +++ b/actions/deleteLeaflet.ts @@ -16,6 +16,52 @@ import { supabaseServerClient } from "supabase/serverClient"; export async function deleteLeaflet(permission_token: PermissionToken) { const client = await pool.connect(); const db = drizzle(client); + + // Get the current user's identity + let identity = await getIdentityData(); + + // Check publication and document ownership in one query + let { data: tokenData } = await supabaseServerClient + .from("permission_tokens") + .select(` + id, + leaflets_in_publications(publication, publications!inner(identity_did)), + leaflets_to_documents(document, documents!inner(uri)) + `) + .eq("id", permission_token.id) + .single(); + + if (tokenData) { + // Check if leaflet is in a publication + const leafletInPubs = tokenData.leaflets_in_publications || []; + if (leafletInPubs.length > 0) { + if (!identity) { + throw new Error("Unauthorized: You must be logged in to delete a leaflet in a publication"); + } + const isOwner = leafletInPubs.some( + (pub: any) => pub.publications.identity_did === identity.atp_did + ); + if (!isOwner) { + throw new Error("Unauthorized: You must own the publication to delete this leaflet"); + } + } + + // Check if there's a standalone published document + const leafletDocs = tokenData.leaflets_to_documents || []; + if (leafletDocs.length > 0) { + if (!identity) { + throw new Error("Unauthorized: You must be logged in to delete a published leaflet"); + } + for (let leafletDoc of leafletDocs) { + const docUri = leafletDoc.documents?.uri; + // Extract the DID from the document URI (format: at://did:plc:xxx/...) + if (docUri && !docUri.includes(identity.atp_did)) { + throw new Error("Unauthorized: You must own the published document to delete this leaflet"); + } + } + } + } + await db.transaction(async (tx) => { let [token] = await tx .select() diff --git a/app/(home-pages)/home/LeafletList/LeafletOptions.tsx b/app/(home-pages)/home/LeafletList/LeafletOptions.tsx index 58287b02..2afc85ca 100644 --- a/app/(home-pages)/home/LeafletList/LeafletOptions.tsx +++ b/app/(home-pages)/home/LeafletList/LeafletOptions.tsx @@ -86,9 +86,15 @@ const DefaultOptions = (props: { const pubStatus = useLeafletPublicationStatus(); const toaster = useToaster(); const { setArchived } = useArchiveMutations(); + const { identity } = useIdentityData(); const tokenId = pubStatus?.token.id; const itemType = pubStatus?.draftInPublication ? "Draft" : "Leaflet"; + // Check if this is a published post/document and if user is the owner + const isPublishedPostOwner = + !!identity?.atp_did && !!pubStatus?.documentUri?.includes(identity.atp_did); + const canDelete = !pubStatus?.documentUri || isPublishedPostOwner; + return ( <> @@ -133,12 +139,14 @@ const DefaultOptions = (props: { {!props.archived ? " Archive" : "Unarchive"} {itemType} - { - e.preventDefault(); - props.setState("areYouSure"); - }} - /> + {canDelete && ( + { + e.preventDefault(); + props.setState("areYouSure"); + }} + /> + )} ); }; -- 2.51.2