uttrflow / uttrflow/uttrflow-swift
Clipboard secret detection masks ordinary Chinese and Japanese sentences after "password:" or "token:", and counts Han and other non-ASCII numerals as digits
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## What happens
Three rules in the named-secret and hex scans assume Latin text. They were run by copying `SecretScanners.swift`, `SecretShapes.swift`, `PatternWindows.swift`, `CardNumberShape.swift` and `ClipKindDetector.swift` verbatim from `origin/main` 26d7bc1 into a throwaway `swiftc` build.
**1. A value only ends at whitespace.** `bareValue` (`Sources/UttrflowClipboard/SecretScanners.swift:337-355`) stops at `character.isWhitespace` or a quote. `bareAssignment` (`:323-334`) then accepts any value of 12 characters or more:
```swift
return (lineEnd, quoted || hasNumber || length >= 12)
```
Chinese and Japanese put no spaces between words, so the rest of the sentence becomes the "value":
| clip | kind |
|---|---|
| `password: 忘れた場合は管理者に連絡してください` | `.secret` |
| `secret: 这是一个秘密不要告诉别人` | `.secret` |
| `APIキーの設定方法 token: 設定画面から発行してください` | `.secret` |
| `password: please contact the admin to reset it` | `.text` |
**2. Any Unicode number counts as a digit.** `:350` is `if character.isNumber { lastNumber = ... }`. `Character.isNumber` is true for 三, 一, ४, ٥ and ½, so a one-character value passes through `hasNumber`:
| clip | kind |
|---|---|
| `pwd: 三` | `.secret` |
| `token: 一つ目` | `.secret` |
| `token: first` | `.text` |
**3. Full-width digits pass the hex rule.** `Sources/UttrflowClipboard/SecretShapes.swift:149` checks `token.allSatisfy(\.isHexDigit)`, and `Character("1").isHexDigit` is true. The entropy rule next to it requires ASCII (`:161-165`); this one doesn't. `注文番号 001234567890012345678900123456789` (an order number in full-width digits) → `.secret`.
A full-width colon (`Password:…`) is not recognised at all. That is the safe direction, and noted only for completeness.
## Why it matters
A masked clip shows as a key icon with its text hidden until revealed (`Sources/UttrflowUX/PanelPresentation.swift:359`). Instructions like "if you forgot your password, contact the administrator", copied from a Japanese or Chinese help page, are hidden in the panel as if they were credentials. The same sentence in English is shown. It doesn't leak anything, but it makes clipboard history less useful for exactly the users whose text doesn't use spaces.
Devanagari, Arabic and other space-separated scripts are not affected by rule 1. They are checked and fine: a long Devanagari word isn't flagged, and Devanagari or Arabic-Indic digits never match the card pattern.
## Acceptance criteria
- An unquoted value also ends where a run of non-Latin letters starts, or counts as a secret only when it looks like one: mostly ASCII letters and digits, or it contains an ASCII digit.
- `hasNumber` counts ASCII digits only.
- The hex rule requires ASCII hex digits.
- `Tests/UttrflowClipboardTests/SecretDetectionTests.swift` adds the six non-Latin examples above to its "not a secret" list (next to `"Change your password: now"`), and every existing secret case in that file stays detected.
Contributor guide
Research direction
Start with the named scanner and shape files: Sources/UttrflowClipboard/SecretScanners.swift, SecretShapes.swift, PatternWindows.swift, CardNumberShape.swift, and ClipKindDetector.swift. Review the cited ranges, then run Tests/UttrflowClipboardTests/SecretDetectionTests.swift. Done means the six non-Latin examples are not detected as secrets, ASCII-only numeric and hex checks behave as specified, and every existing secret case still passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, swift
- Domain
- desktop, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100