fix: partage dirigé — ACL court-circuitée après résolution Partage/ + chemin canonique au token #196
- le partage EST l'autorisation: plus de 403 'Accès refusé à la vault' pour un destinataire sans accès au vault émetteur (api_file, raw, download) - chemin virtuel canonique Partage/<token>/<nom> — désambiguïse les homonymes, fallback par nom conservé - 'reçu' = partagé_avec contient l'utilisateur: un admin ne voit plus les partages des autres comme reçus (fix File not found: Partage/…) - +3 tests (14 total)
This commit is contained in:
@@ -62,7 +62,11 @@ const DashboardSharedWidget = {
|
||||
if (empty) empty.style.display = "none";
|
||||
const me = (AuthManager.getUser() || {}).username;
|
||||
grid.innerHTML = shares.map(s => {
|
||||
const received = me && s.created_by && s.created_by !== me;
|
||||
// Reçu = adressé à moi (et pas créé par moi). Un admin voit TOUS les
|
||||
// partages via /api/shares — ceux des autres comptes ne sont pas
|
||||
// « reçus » pour lui : ils ne se résolvent pas dans son Partage/.
|
||||
const received = me && s.created_by && s.created_by !== me
|
||||
&& Array.isArray(s.shared_with) && s.shared_with.includes(me);
|
||||
const actions = received
|
||||
? `<button class="shared-open-btn">${t('dashboard.open_btn')}</button>`
|
||||
: `<button class="shared-copy-btn" data-url="${window.location.origin}/s/${s.token}">${t('dashboard.copy_btn')}</button>
|
||||
|
||||
+16
-11
@@ -32,7 +32,10 @@ async function _loadReceivedShares() {
|
||||
if (!me) return [];
|
||||
try {
|
||||
const shares = await api("/api/shares");
|
||||
return shares.filter(s => s.created_by && s.created_by !== me);
|
||||
// Adressés à moi uniquement : un admin voit tous les partages via
|
||||
// /api/shares, ceux des autres ne sont pas dans SON Partage/.
|
||||
return shares.filter(s => s.created_by && s.created_by !== me
|
||||
&& Array.isArray(s.shared_with) && s.shared_with.includes(me));
|
||||
} catch { return []; }
|
||||
}
|
||||
|
||||
@@ -366,16 +369,17 @@ async function incrementalLoadDirectory(vaultName, dirPath, container) {
|
||||
const shareSub = el("div", { class: "tree-children collapsed", id: `dir-${vaultName}-Partage` });
|
||||
item.shares.forEach((s) => {
|
||||
const name = (s.path || "").split("/").pop().replace(/\.md$/i, "");
|
||||
const fItem = el("div", { class: "tree-item", "data-vault": vaultName, "data-path": `Partage/${s.path.split("/").pop()}`, "data-type": "file", "data-share-token": s.token }, [_sharedIcon(), el("span", { class: "tree-item-text" }, [document.createTextNode(name)])]);
|
||||
const virtualPath = `Partage/${s.token}/${s.path.split("/").pop()}`;
|
||||
const fItem = el("div", { class: "tree-item", "data-vault": vaultName, "data-path": virtualPath, "data-type": "file", "data-share-token": s.token }, [_sharedIcon(), el("span", { class: "tree-item-text" }, [document.createTextNode(name)])]);
|
||||
fItem.title = t("dashboard.shared_by", { user: s.created_by || "" });
|
||||
fItem.addEventListener("click", () => {
|
||||
scrollTreeItemIntoView(fItem, false);
|
||||
// #196 : ouverture en onglet applicatif — /api/file résout Partage/
|
||||
// vers le fichier source (lecture seule).
|
||||
// #196 : ouverture en onglet applicatif — /api/file résout
|
||||
// Partage/<token>/<nom> vers le fichier source (lecture seule).
|
||||
if (window.innerWidth <= 768) {
|
||||
TabManager.openPersistent(vaultName, `Partage/${(s.path || "").split("/").pop()}`);
|
||||
TabManager.openPersistent(vaultName, virtualPath);
|
||||
} else {
|
||||
TabManager.openPreview(vaultName, `Partage/${(s.path || "").split("/").pop()}`);
|
||||
TabManager.openPreview(vaultName, virtualPath);
|
||||
}
|
||||
closeMobileSidebar();
|
||||
});
|
||||
@@ -736,16 +740,17 @@ async function loadDirectory(vaultName, dirPath, container) {
|
||||
const shareSub = el("div", { class: "tree-children collapsed", id: `dir-${vaultName}-Partage` });
|
||||
item.shares.forEach((s) => {
|
||||
const name = (s.path || "").split("/").pop().replace(/\.md$/i, "");
|
||||
const fItem = el("div", { class: "tree-item", "data-vault": vaultName, "data-path": `Partage/${s.path.split("/").pop()}`, "data-type": "file", "data-share-token": s.token }, [_sharedIcon(), el("span", { class: "tree-item-text" }, [document.createTextNode(name)])]);
|
||||
const virtualPath = `Partage/${s.token}/${s.path.split("/").pop()}`;
|
||||
const fItem = el("div", { class: "tree-item", "data-vault": vaultName, "data-path": virtualPath, "data-type": "file", "data-share-token": s.token }, [_sharedIcon(), el("span", { class: "tree-item-text" }, [document.createTextNode(name)])]);
|
||||
fItem.title = t("dashboard.shared_by", { user: s.created_by || "" });
|
||||
fItem.addEventListener("click", () => {
|
||||
scrollTreeItemIntoView(fItem, false);
|
||||
// #196 : ouverture en onglet applicatif — /api/file résout Partage/
|
||||
// vers le fichier source (lecture seule).
|
||||
// #196 : ouverture en onglet applicatif — /api/file résout
|
||||
// Partage/<token>/<nom> vers le fichier source (lecture seule).
|
||||
if (window.innerWidth <= 768) {
|
||||
TabManager.openPersistent(vaultName, `Partage/${(s.path || "").split("/").pop()}`);
|
||||
TabManager.openPersistent(vaultName, virtualPath);
|
||||
} else {
|
||||
TabManager.openPreview(vaultName, `Partage/${(s.path || "").split("/").pop()}`);
|
||||
TabManager.openPreview(vaultName, virtualPath);
|
||||
}
|
||||
closeMobileSidebar();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user