Fix typedstream attributedBody recovery for 32-126 byte messages whose length byte is printable ASCII, and keep the regression covered across the parser edge cases.\n\nCo-authored-by: Sagar Dagdu <shags032@gmail.com>
* fix(security): clamp IPC dirs to 0700 and reject symlinked paths
Threat model: a same-UID attacker (another user process, a sandboxed peer
that can reach the home dir) can drop a file or symlink into the RPC
inbox, or supply an attachment path that points at a sensitive file via
a parent-directory symlink, and have Messages.app exfiltrate it as an
attachment to an attacker-controlled handle.
Mitigations applied at every IPC boundary:
- Mode 0700 on .imsg-rpc/, .imsg-rpc/in/, .imsg-rpc/out/ creation.
Final chmod handles dirs that already existed 0755 from prior
unsandboxed runs.
- Refuse any RPC queue path or attachment path where any component
(final or parent) is a symbolic link. Walking each component with
lstat() — done by SecurePath.hasSymlinkComponent in IMsgCore and the
pathHasSymlinkComponent twin in the dylib — catches parent-directory
links that realpath()-vs-lexical comparison misses (macOS rewrites
/tmp -> /private/tmp, breaking that approach for legitimate paths).
- Strict throws for queue dir creation and cleanup in MessagesLauncher
(was `try?` swallowing errors), and for ensureDirectory in
IMsgBridgeClient. Bridge refuses to start instead of operating on an
insecure path.
Tests cover both final-component and parent-component symlink detection
in SecurePath. Toolchain on this machine lacks swift-testing; tests
build clean and ship to be run by Xcode on the maintainer's box.
* fix: allow trusted system path aliases
---------
Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Decode typedstream attributedBody segments that use 0x81/0x82 length prefixes so long fallback message text is preserved in history/watch output.
Also records the fix in the 0.7.0 changelog.
Co-authored-by: Sagar Dagdu <shags032@gmail.com>
Port the BlueBubbles-inspired IMCore bridge surface into imsg with rich sends, message mutation, chat management, account/nickname introspection, live bridge events, and v2 UUID-keyed IPC.
Fixes#60.
Co-authored-by: Omar Shahine <omarshahine@users.noreply.github.com>
iMessage writes multiple rows to chat.db for the same URL when the rich
link preview resolves. Both rows have balloon_bundle_id set to
'com.apple.messages.URLBalloonProvider' with identical text and sender
but different ROWIDs and timestamps.
This causes downstream consumers (like OpenClaw) to process the same
URL message twice, burning tokens and producing duplicate responses.
Fix: in messagesAfter(), track seen (sender, text) pairs for URL balloon
messages and skip duplicates within the same batch.
This field helps distinguish between messages actually sent by the local
user vs messages received on a secondary phone number registered with
the same Apple ID.
When is_from_me is true but destination_caller_id differs from the
user's own numbers, the message was actually received from another
device/person messaging that secondary number.
This enables tools like Clawdbot to properly detect inbound messages
on secondary iMessage phone numbers.
Adds thread_originator_guid field to JSON output for history, watch, and RPC.
This field contains the GUID of the message being replied to when users
use iMessage's inline reply feature.
This is the correct field for reply detection - it matches the UI's reply
target, unlike reply_to_guid which can point to different messages.
Closes#30
Co-Authored-By: Claude <noreply@anthropic.com>
Apply --start/--end/--participants in SQL so LIMIT applies after filtering (CLI history + RPC messages.history). Add regressions proving filtered windows work with small limits.
Messages seems to expect the attachments to be in the Attachments directory, otherwise upload fails with error 25. Set up `~/Library/Messages/Attachments/imsg/<UUID>/<filename>` for imsg.