05/29 Fixed a shared item isn't auto updated when it's modified by owner

This commit is contained in:
2026-05-29 14:58:11 -04:00
parent 5f8ce4b5de
commit 977805f5e7
3 changed files with 44 additions and 10 deletions
+12 -1
View File
@@ -145,6 +145,7 @@ def update_item(item_id):
# Re-encrypt accepted shared copies if the owner provided updated ciphertext.
# Each entry: { share_id, enc_data, iv, enc_name?, iv_name? }
from app.models.shared_item import SharedItem
updated_share_ids = []
for upd in (data.get('shared_updates') or []):
share = SharedItem.query.filter_by(
id=upd.get('share_id'),
@@ -157,6 +158,7 @@ def update_item(item_id):
if upd.get('enc_name') is not None:
share.enc_name = upd['enc_name']
share.iv_name = upd.get('iv_name')
updated_share_ids.append(share.id)
try:
db.session.flush()
@@ -168,6 +170,15 @@ def update_item(item_id):
detail=f'Updated {item.item_type} item (id={item.id})',
ip_address=client_ip(),
)
if updated_share_ids:
AuditLog.log(
user_id=g.current_user_id,
action='shared_item.update',
resource_type='shared_item',
resource_id=item.id,
detail=f'Re-encrypted {len(updated_share_ids)} shared copy(ies) for vault item (id={item.id}), share_ids={updated_share_ids}',
ip_address=client_ip(),
)
db.session.commit()
except Exception:
db.session.rollback()
@@ -320,4 +331,4 @@ def audit_bulk_export():
ip_address=client_ip(),
)
db.session.commit()
return jsonify({'logged': len(valid_ids)}), 200
return jsonify({'logged': len(valid_ids)}), 200
+20 -8
View File
@@ -2212,8 +2212,20 @@ const Vault = (() => {
return;
}
try {
// Always fetch fresh share data from the server so the grantee sees
// the owner's latest version, not the ciphertext that was baked into
// the button's data-* attributes when the tab was last rendered.
const shareId = parseInt(btn.dataset.viewShare);
const inboxRes = await apiFetch("/api/sharing/inbox");
if (!inboxRes) return;
const inbox = await inboxRes.json();
const freshShare = inbox.find((s) => s.id === shareId);
if (!freshShare || !freshShare.owner_public_key) {
showToast("Share not found or owner key unavailable.", "error");
return;
}
const ownerPubKey = await SharingCrypto.importPublicKey(
btn.dataset.ownerKey,
freshShare.owner_public_key,
);
const sharedKey = await SharingCrypto.deriveSharedKey(
SharingSession.getKey(),
@@ -2221,21 +2233,21 @@ const Vault = (() => {
);
const plain = await SharingCrypto.decryptShare(
sharedKey,
btn.dataset.enc,
btn.dataset.iv,
freshShare.enc_data,
freshShare.iv,
);
// Decrypt the item name if an encrypted version is available.
// Falls back to the non-sensitive label for legacy shares.
let displayName = btn.dataset.name;
if (btn.dataset.encName && btn.dataset.ivName) {
let displayName = freshShare.item_name;
if (freshShare.enc_name && freshShare.iv_name) {
const decrypted = await SharingCrypto.decryptName(
sharedKey,
btn.dataset.encName,
btn.dataset.ivName,
freshShare.enc_name,
freshShare.iv_name,
);
if (decrypted) displayName = decrypted;
}
showSharedItemDetails(displayName, btn.dataset.type, plain);
showSharedItemDetails(displayName, freshShare.item_type, plain);
} catch (err) {
showToast("Could not decrypt: " + err.message, "error");
}