Repository navigation
Releases: appfide/nija
Release list
Nija 0.5.0
Unsigned builds: see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt, and their origin with
gh attestation verify <file> --repo appfide/nija.
An SPDX bill of materials ships with the release.
What changed in 0.5.0
Added
- Delete history (Settings → Data): Delete history on this device removes every local clip, pinned ones too, and leaves the database alone; clips already there are not downloaded again. Delete history in the database removes every clip and deletion record from the connected database for all devices. Devices, pairing and keys stay, so sync carries on. In a signed group only the admin, or a member it gave the permission, can do this.
- Pause a device (Settings → Devices → Manage devices, admin only): a paused device stays paired and keeps its credentials but sends and receives nothing. Clips copied elsewhere while it is paused never reach it, and what it copies meanwhile stays on it. Resume brings it back. Unlike Block, it does not have to be paired again. Devices on 0.4.2 or older do not know this status and keep syncing.
- Permissions and more admins (Manage devices, admin of a signed group): Permissions… lets a member delete the database history without becoming an admin; Make admin… hands a paired device the group admin key, sealed to it, so it can manage the group too. Both are signed with the membership, so a member cannot grant them to itself. Supabase and PocketBase need two new device columns for this (upgrade notes); without them the app refuses the grant and leaves the device unchanged.
- Leave this group and Start a new group on this database (Settings → Devices). Leaving removes this device from the group and forgets its credentials and keys; starting a new group wipes the database's clips and devices and makes this device the admin of a fresh group with new keys. The second is also the way back when the admin device is lost.
- Sync with the database switch (Settings → Sync): turns database sync off on this device only. Clipboard history keeps being recorded locally; nothing copied while it is off is sent, and clips from other devices arrive once it is back on.
Changed
- Universal Clipboard no longer relabels clips. A copy that reached a Mac or iPhone through Apple's Universal Clipboard was recorded again on that device under its own name, and the original from the device that made it was then dropped as an echo, so every device showed the clip as its own. While syncing, Nija now leaves such copies to the device they came from (Settings → Capture → Leave Universal Clipboard to its device, on by default).
- A clip can only be deleted from the group by the device that copied it. On every other device the menu now says Delete on this device and only removes the local copy. Before, deleting another device's clip pushed a deletion signed with the wrong key: the database copy was emptied, but signed groups rejected the deletion, so other devices kept the clip and the device that copied it never saw the change. The sync engine now refuses to push such a deletion.
- Dropping and recreating the database tables no longer disconnects every device. A device whose row is missing now disconnects only if a device it already knew is still listed; otherwise the database was reset, and it registers again (the admin also signs its own row again), whichever device gets back first. Before, each device concluded it had been removed and deleted its credentials and passphrase.
- Supabase with missing tables or columns now reports Connected plus a schema check listing what is missing, and two ways to fix it. Set up automatically asks once for a Supabase personal access token and runs the setup through the Supabase Management API; the token is sent only to Supabase, for that one request, is never stored, and clipboard capture is paused while the dialog is open so copying it is not recorded. Copy setup SQL gives the same script to run by hand: generated for your table names and sign-in mode, it creates the tables or adds the missing columns, turns on row level security and enables realtime, and is safe to run again. Before, the app said Connection failed: Could not find the table 'public.clip_items' in the schema cache. Sync shows the same advice and retries until the tables exist.
- A keychain that times out is no longer read as "no keys": this device's signing keys are never replaced because of a slow keychain prompt (peers would reject every clip signed with new ones), and a credential delete the keychain did not confirm is retried rather than coming back on the next launch. Secret fields of the database form are read together, so a pending prompt costs one wait instead of one per field.
- Supabase personal access tokens (
sbp_…) are recognised as credentials: Skip keys and tokens skips them and logs redact them. - The macOS app renders with Skia instead of Impeller: on Flutter 3.47 Impeller dropped or garbled single letters in labels.
- App Store and Mac App Store builds (
STORE_BUILD=true, set byscripts/build_appstore.sh) leave out the installers for other platforms and, in the sandboxed Mac build, Start at login. The script now also regenerates the Flutter config before the macOS archive (it used to ship the version of whatever was built last) and puts the provisioning profile on the Release configuration. - On iPad and other wide layouts the side rail keeps clear of the status bar; the database tiles no longer overflow on 430 pt wide phones.
- Store screenshots are generated from the app itself:
test_screenshots/store_shots_test.dartrenders the screens with demo data,tool/store_shots/compose.pyframes them. - CI and release builds use Flutter 3.47.5 (from 3.44.4).
What's Changed
Full Changelog: v0.4.2...v0.5.0
Nija 0.4.2
Unsigned builds: see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt, and their origin with
gh attestation verify <file> --repo appfide/nija.
An SPDX bill of materials ships with the release.
What's Changed
- docs(release): script the macOS signing setup around Apple's portal by @dhipin in #35
- feat(store): build and upload App Store builds for iOS and macOS by @dhipin in #36
- feat(history): filters, keyboard control, clip preview and tray recents by @dhipin in #37
- chore(release): 0.4.2 by @dhipin in #39
Full Changelog: v0.4.1...v0.4.2
Nija 0.4.1
Unsigned builds: see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt, and their origin with
gh attestation verify <file> --repo appfide/nija.
An SPDX bill of materials ships with the release.
What changed in 0.4.1
Added
- Every desktop installer is now launched before it is published. Verification proved an installer contained the right app; it could not tell whether that app starts.
scripts/smoke_launch.shunpacks the dmg, deb and Windows zip, starts the binary hidden, and fails the release if it is not still running seconds later — the signature of a build that cannot find a library or dies initialising its database. Android and iOS are not covered: launching them needs an emulator or simulator, and the actions that provide one are not on this repository's allowlist.
What's Changed
- ci(release): launch every desktop build before publishing it (0.4.1) by @dhipin in #33
- fix(release): find the Windows executable whatever its case by @dhipin in #34
Full Changelog: v0.4.0...v0.4.1
Nija 0.4.0
Unsigned builds: see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt, and their origin with
gh attestation verify <file> --repo appfide/nija.
An SPDX bill of materials ships with the release.
What changed in 0.4.0
Changed
- The app is now called Nija. निज (nija) is Sanskrit for "one's own" — the name says what the product is: your clipboard, on your database, under your keys. The About page and the README explain it. Nothing about how syncing, encryption or pairing works has changed.
- Bundle identifiers are now
com.appfide.nijaon every platform (fromcom.appfide.clipboardSync/com.appfide.clipboard_sync). The operating system treats a new identifier as a different app, so 0.3.0 will not upgrade in place: install Nija, pair it as you would a new device, and remove the old app afterwards. Local history kept by the old install stays in its own sandbox and is not carried over; anything already in your database syncs back down on first run. - Pairing codes now start with
NIJA1.instead ofCSYNC1., and derive from a matching label. A device still running 0.3.0 cannot pair with one running this build — upgrade both. - The repository, the Flutter app and the core package are now
appfide/nija,apps/nijaandpackages/nija_core. Live-backend tests readNIJA_TEST_<BACKEND>_*environment variables instead ofCLIPSYNC_TEST_*. - Noto Sans Devanagari (SIL OFL 1.1) ships with the app so the name renders in its own script on every platform, not only where the OS happens to have a Devanagari face.
Added
- Every release is now verified before it is published.
scripts/verify_artifacts.shopens each installer and checks it is the app it claims to be — bundle identifiercom.appfide.nija, the version being released, a plausible binary size, and the signing state the release promises (Developer ID plus a notarization staple on macOS, a verified upload-key signature on Android). A build carrying the wrong identifier or last version's number now fails the release rather than reaching users. - Build provenance. Every published file carries a GitHub-signed attestation naming the workflow, commit and runner that produced it:
gh attestation verify <file> --repo appfide/nija. A checksum only proves a file is intact; provenance proves where it came from, which matters because whoever can replace the file can replace the checksum beside it. - An SPDX software bill of materials ships with each release and is covered by
SHA256SUMS.txt. - Release notes now lead with the CHANGELOG section for that version instead of only a list of commit subjects.
- Releases are serialised: a second version bump queues behind the one in flight instead of racing it for the tag.
Unchanged (deliberately)
- The passphrase-to-key derivation, the keyed content fingerprint and the key-envelope labels still carry their original
clipsync-*v1 names. They are wire constants baked into data already sitting in users' databases: renaming them would make existing clips undecryptable and break de-duplication. The app's name is not part of its key schedule.
What's Changed
- rename: Clipboard Sync is now Nija (0.4.0) by @dhipin in #25
- ci(release): build the SBOM without a third-party action by @dhipin in #30
- fix(release): compare version cores, not packager spellings by @dhipin in #31
- fix(release): stop grep -q from failing the checks it passes by @dhipin in #32
Full Changelog: v0.3.0...v0.4.0
Clipboard Sync 0.3.0
Unsigned builds: see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt.
What's Changed
- test(security): assert envelopes directly, not by substring by @dhipin in https://github.com/appfide/clipboard-sync/pull/9
- build(deps): Bump the actions group with 3 updates by @dependabot[bot] in https://github.com/appfide/clipboard-sync/pull/8
- build(deps): Bump flutter_secure_storage from 11.0.0 to 11.1.1 in /apps/clipboard_sync by @dependabot[bot] in https://github.com/appfide/clipboard-sync/pull/7
- build(deps): Bump drift from 2.34.4 to 2.35.0 in /apps/clipboard_sync by @dependabot[bot] in https://github.com/appfide/clipboard-sync/pull/6
- build(deps): Bump drift_dev from 2.34.6 to 2.35.0 in /apps/clipboard_sync by @dependabot[bot] in https://github.com/appfide/clipboard-sync/pull/5
- build(deps): restore Flutter-pinned transitives in the lock by @dhipin in https://github.com/appfide/clipboard-sync/pull/10
- build(deps): Bump the actions group with 2 updates by @dependabot[bot] in https://github.com/appfide/clipboard-sync/pull/14
- build(deps): bump flutter_secure_storage to 11.2.0 and mobile_scanner to 7.4.2 by @dhipin in https://github.com/appfide/clipboard-sync/pull/15
- feat: new app icon across every platform by @dhipin in https://github.com/appfide/clipboard-sync/pull/16
- ci: sign and notarize the macOS dmg when the secrets exist by @dhipin in https://github.com/appfide/clipboard-sync/pull/17
- feat: in-app download page for every platform by @dhipin in https://github.com/appfide/clipboard-sync/pull/18
- fix: say what a network failure means instead of printing it by @dhipin in https://github.com/appfide/clipboard-sync/pull/19
- fix(macos): keep running in the menu bar when the window closes by @dhipin in https://github.com/appfide/clipboard-sync/pull/20
- fix(security): keyed content hash, and clear pre-encryption clips by @dhipin in https://github.com/appfide/clipboard-sync/pull/21
- fix(security): migrate the leaky fingerprints already in the database by @dhipin in https://github.com/appfide/clipboard-sync/pull/22
- style: normalise punctuation across docs, comments and UI copy by @dhipin in https://github.com/appfide/clipboard-sync/pull/23
- chore(release): 0.3.0 by @dhipin in https://github.com/appfide/clipboard-sync/pull/24
New Contributors
- @dependabot[bot] made their first contribution in https://github.com/appfide/clipboard-sync/pull/8
Full Changelog: https://github.com/appfide/clipboard-sync/compare/v0.2.1...v0.3.0
Clipboard Sync 0.2.1
Security
- Key rotation now issues envelopes only to the engine's rollback-aware trusted set. Before, a device whose older admin-signed row had been restored after a block (a rollback the engine already ignored for clips) could still receive the new passphrase. Found by running the attacker suite against a live Supabase project.
Changed
- Live contract tests allow real websockets time to subscribe; new
live_attacker_test.dartruns the signed-group threat model against a real database (dart test -t live).
Unsigned builds — see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt.
What's Changed
- fix(security): rotate keys only to the rollback-aware trusted set (0.2.1) by @dhipin in https://github.com/appfide/clipboard-sync/pull/4
Full Changelog: https://github.com/appfide/clipboard-sync/compare/v0.2.0...v0.2.1
Clipboard Sync 0.2.0
Added
- Secure by default: choosing a database now encrypts the group with a random passphrase and signs it with an admin key (switch on the database screen); other devices receive the passphrase sealed through pairing. Settings → Privacy → Show passphrase reveals it for manual joins.
- Device pairing: Settings → Devices → Add a device shows a QR code (or a copyable code) plus an 8-digit PIN; the other device scans or pastes it under Join another group (also offered on the welcome screen). The code carries the database settings encrypted with the PIN (Argon2id → AES-256-GCM), is valid for 5 minutes and is never recorded in clipboard history. The host chooses the new device's role and access duration and whether to share the passphrase (delivered sealed to the new device, never inside the code).
- Device management: list every device with presence, block / unblock, remove, forget, change role (Send & receive, Send only, Receive only) and set temporary access. A blocked, removed or expired device stops itself, deletes its credentials, keys and passphrases, and tells the user. In a signed group these decisions are verified cryptographically — see
docs/devices.md. - Send to… in the history menu pushes a clip to one device only (
target_device_id). - Capture filters: Pause capture (also in the tray menu), Skip password-manager content (macOS concealed/transient pasteboard types, Windows
ExcludeClipboardContentFromMonitorProcessing, Android 13+EXTRA_IS_SENSITIVE; on by default) and Skip keys and tokens (credential-pattern heuristic). - Signed groups: every device has an Ed25519 / X25519 identity; every clip is signed and verified against the sender's admin-signed key; membership changes (status, role, expiry, keys, admin flag, key envelope) are signed by a group admin key with rollback protection. Holding the database credentials is no longer enough to pose as a device, lift a block, or take over the group. Settings → Devices → Secure this group upgrades existing groups; members confirm the admin fingerprint once.
- Encryption key rotation: the admin issues a fresh random passphrase sealed to each verified device (X25519 + AES-GCM envelope covered by the admin signature). Removed or blocked devices cannot read clips sealed after the rotation; older history stays readable through a local keyring. Pairing delivers the passphrase the same way — it never travels inside the QR code.
- Device rows carry
status,role,expires_at,paired_by,app_version,sign_pub,box_pub,admin,admin_pub,membership_version,membership_sig,key_version,key_envelope; clips carrytarget_device_id,key_version,sig. Supabase and PocketBase need the upgrade snippet in their guide; other backends need nothing.
Changed
- Heartbeats write only presence fields, so a block set by another device is never overwritten.
- Local database schema v2 (adds
target_device_id); migrates automatically.
Unsigned builds — see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt.
What's Changed
- docs(changelog): describe the 0.1.0 release by @dhipin in https://github.com/appfide/clipboard-sync/pull/1
- fix(sync): single engine start, iOS-safe capture start, UUID test fixtures by @dhipin in https://github.com/appfide/clipboard-sync/pull/2
- feat(devices): pairing codes, device management, roles, expiry, capture filters by @dhipin in https://github.com/appfide/clipboard-sync/pull/3
New Contributors
- @dhipin made their first contribution in https://github.com/appfide/clipboard-sync/pull/1
Full Changelog: https://github.com/appfide/clipboard-sync/compare/v0.1.0...v0.2.0
Clipboard Sync 0.1.0
Unsigned builds — see docs/release.md for Gatekeeper / SmartScreen steps.
Verify downloads with SHA256SUMS.txt.
Full Changelog: https://github.com/appfide/clipboard-sync/commits/v0.1.0