Skip to content

Add Security-Scoped Bookmarks for local file access#3

Open
fxd0h wants to merge 1 commit intob451c:mainfrom
fxd0h:feature/security-scoped-bookmarks
Open

Add Security-Scoped Bookmarks for local file access#3
fxd0h wants to merge 1 commit intob451c:mainfrom
fxd0h:feature/security-scoped-bookmarks

Conversation

@fxd0h
Copy link
Contributor

@fxd0h fxd0h commented Mar 3, 2026

Summary

QuickMD can't display local images (e.g. ![](screenshot.png)) in sandboxed builds because the app only gets read access to the file the user opens, not to sibling files in the same directory.

This PR adds a SandboxAccessManager that handles Security-Scoped Bookmarks:

  1. When a local image fails to load (sandbox blocks access), the user is prompted via NSOpenPanel to grant folder access
  2. The bookmark is persisted in UserDefaults so subsequent launches restore access silently
  3. If the user denies access, a placeholder with a "Grant Folder Access" button is shown for retry
  4. If the image file simply doesn't exist, the standard image error view is shown (not the access prompt)

Changes

File Change
SandboxAccessManager.swift [NEW] @MainActor singleton managing bookmark creation, persistence, and restoration
ImageBlockView.swift Try-first/prompt-on-failure flow with retry placeholder UI
project.pbxproj File reference for SandboxAccessManager.swift
QuickMD.entitlements com.apple.security.files.bookmarks.app-scope entitlement
CHANGELOG.md v1.4.0 entry

Design Decisions

  • On-demand prompting: The NSOpenPanel only appears when an image actually fails to load, not on every file open. This avoids unnecessary prompts for markdown files without local images.
  • @MainActor isolation: SandboxAccessManager is marked @MainActor for thread safety since ImageBlockView calls it from async contexts.
  • File existence check: Before assuming sandbox denial, we check if the file actually exists. Missing files show the standard error view, not the access prompt.
  • Retry UX: If the user cancels the prompt, a placeholder with 🔒 icon, filename, and "Grant Folder Access" button is shown. Clicking it re-triggers the prompt.

Testing

Tested with a signed build (sandbox enforced):

  • ✅ Local image that exists → sandbox blocks → prompt appears → user grants → image loads
  • ✅ Image file doesn't exist → standard error view (no access prompt)
  • ✅ Markdown without images → no prompt appears
  • ✅ Subsequent opens → bookmark restored silently, no prompt

Fully App Store compliant — no temporary sandbox exceptions needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant