From bb54f0451f45b994ec827e96948b44c915c90134 Mon Sep 17 00:00:00 2001 From: Sean Starkey Date: Mon, 1 Jun 2026 19:21:01 -0600 Subject: [PATCH] Fix shared note ownership detection --- src/main.jsx | 58 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/main.jsx b/src/main.jsx index 2a6b667..1c14b3a 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -55,7 +55,14 @@ function noteContent(note) { } function noteOwner(note) { - return note?.owner || note?.ownerId || note?.createdBy || note?.userId || ""; + return principalLabel(note?.owner || note?.ownerId || note?.createdBy || note?.userId); +} + +function principalLabel(value) { + if (!value) return ""; + if (typeof value === "string" || typeof value === "number") return String(value); + if (typeof value !== "object") return ""; + return value.username || value.email || value.id || value._id || value.name || ""; } function extractToken(payload) { @@ -696,10 +703,51 @@ function upsertNote(notes, note) { } function ownsNote(note, currentUser) { - const owner = String(noteOwner(note) || "").toLowerCase(); - const user = String(currentUser || "").toLowerCase(); - if (!owner || !user) return !note?.sharedWith && !note?.shared; - return owner === user || owner.includes(user) || user.includes(owner); + if (note?.canEdit === false || note?.readOnly === true) return false; + if (typeof note?.owned === "boolean") return note.owned; + if (typeof note?.isOwner === "boolean") return note.isOwner; + + const ownerValues = principalValues(note?.owner || note?.ownerId || note?.createdBy || note?.userId); + const userValues = principalValues(currentUser); + if (ownerValues.length && userValues.length) { + return ownerValues.some((owner) => userValues.includes(owner)); + } + + return !hasSharedAccessMarker(note); +} + +function principalValues(value) { + if (!value) return []; + if (Array.isArray(value)) return uniqueValues(value.flatMap(principalValues)); + if (typeof value === "object") { + return uniqueValues( + ["username", "email", "id", "_id", "name"] + .flatMap((key) => principalValues(value[key])) + .filter(Boolean), + ); + } + + const normalized = String(value).trim().toLowerCase(); + if (!normalized) return []; + const values = [normalized]; + const [localPart] = normalized.split("@"); + if (normalized.includes("@") && localPart) values.push(localPart); + return uniqueValues(values); +} + +function uniqueValues(values) { + return [...new Set(values)]; +} + +function hasSharedAccessMarker(note) { + return Boolean( + note?.shared === true || + note?.isShared === true || + note?.sharedBy || + note?.sharedFrom || + note?.sharedWith || + String(note?.access || note?.permission || "").toLowerCase().includes("read"), + ); } createRoot(document.getElementById("root")).render();