uttrflow / uttrflow/uttrflow-swift

Clipboard history files and copied pictures are created 0644 in 0755 folders, unlike recordings, which are 0600

Open Beginner friendly
#656 0 comments 0 reactions 0 assignees View on GitHub
area:clipboard bug good first issue P0 security
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## What happens

- `ClipboardStore.persist` writes `clipboard.v1.json` and `saved.v1.json` with `JSONEncoder().encode(clips).write(to: url, options: .atomic)` after a plain `createDirectory(..., withIntermediateDirectories: true)` (`Sources/UttrflowClipboard/ClipboardStore.swift:483-485`).
- `ClipboardStore.keep` writes each picture with `data.write(to:)` into `Images/` created the same way (`:203-205`).
- No attributes are passed and nothing sets POSIX permissions afterwards. Under the default umask of 022, the files come out `-rw-r--r--` and the folders `drwxr-xr-x`, as seen on a real install.

Recordings are already handled: `RecordingWriter` opens with `0o600` (`Sources/UttrflowAudio/RecordingWriter.swift:77`), and so does the instance lock (`Sources/UttrflowCore/Support/SingleInstanceLock.swift:42`).

What protects the clipboard files today is only that `~/Library` and `~/Library/Application Support` are `drwx------` by default. A copy or archive that keeps the files' own modes (a migration, a `tar`/`rsync` of the folder, a shared external disk) has no such protection, and neither does a Mac where someone has loosened those folders.

## Why it matters

The clipboard file holds concealed password-manager copies in plain text (#483) and every copied screenshot. It is the most sensitive file the app writes, and it has the loosest permissions of any of them.

## Acceptance criteria

- `clipboard.v1.json`, `saved.v1.json` and each file in `Images/` are created with mode `0600`; the `Uttrflow/` and `Images/` folders with `0700`. Existing files are tightened on the next write.
- A test in `Tests/UttrflowClipboardTests/ClipboardStoreTests.swift` writes a clip and a picture in a temporary directory and asserts the modes via `FileManager.attributesOfItem(atPath:)[.posixPermissions]`.
- Optional follow-up: the same helper applied to the history, dictionary, snippets and predict stores. That can be one small issue each.

## Where to start

- Add a small helper (for example, in `Sources/UttrflowCore/Support/LocalStore.swift`) that creates a directory with `[.posixPermissions: 0o700]` and sets `0o600` on a file after an atomic write. An atomic write replaces the file, so set the mode after writing.
- Call it from `ClipboardStore.persist` and `ClipboardStore.keep`.
- Extend `Tests/UttrflowClipboardTests/ClipboardStoreTests.swift`.
- Run `make verify`. See `CONTRIBUTING.md`.
- Size: small, about 30 lines plus tests.

Contributor guide

Open the contributing guide

Research direction

Start with Sources/UttrflowClipboard/ClipboardStore.swift at persist and keep, then inspect the existing permission handling in RecordingWriter.swift and SingleInstanceLock.swift. Extend Tests/UttrflowClipboardTests/ClipboardStoreTests.swift to write a clip and picture in a temporary directory and verify file and folder modes. Run make verify; done means the listed clipboard files use 0600 and Uttrflow/Images folders use 0700, including existing items on the next write.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, swift
Domain
desktop, security
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
90/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.