Commit graph

7 commits

Author SHA1 Message Date
Scott Reimers
481e1c8435 Network-wide announcements signed by the bootstrap anchor posting id
New primitive: `VisibilityIntent::Announcement`, a public post whose
author MUST be the hardcoded bootstrap anchor posting identity
(`DEFAULT_ANCHOR_POSTING_ID`) and whose content carries an ed25519
signature by that key. Forged announcements (any other author, or
bad signature) are rejected by `control::receive_post` before storage
— they never enter the DB and never propagate via neighbor-manifest
diffs. Only the real anchor can publish announcements, and it does so
sparingly as part of the release deploy flow.

Uses release announcements to drive an in-app upgrade banner:
- Anchor publishes a signed `{category:release, version, channel,
  download_url, ...}` post during every deploy.
- Clients receive it via the normal CDN; `apply_announcement_if_applicable`
  stores the latest-per-category/channel in the settings kv, keyed
  e.g. `announcement:release:stable`.
- Welcome screen checks storage on startup; if the stored release
  version > CARGO_PKG_VERSION on the user's selected channel, a banner
  appears with a Download button that opens the system browser.
- Settings gets "Updates" section with Stable / Beta radio + Check-now
  button + current status line.

Core:
- `DEFAULT_ANCHOR_POSTING_ID: NodeId` constant (32 bytes, the anchor's
  current posting id — `17af141956ae...`).
- New `VisibilityIntent::Announcement` variant; feed filters in all 6
  `get_feed*` / `list_posts*` query sites updated to also exclude the
  new intent AND the pre-existing `GroupKeyDistribute` intent.
- `types::AnnouncementContent` + `ReleaseAnnouncement` structs.
- `crypto::{sign,verify}_announcement` — length-prefixed field digest
  with a "has release" 1-byte flag.
- New `announcement` module with `verify_announcement_post`,
  `apply_announcement_if_applicable`, `latest_release`,
  `build_announcement_post`, and a `StoredAnnouncement` envelope saved
  to settings so the UI can render without a full post scan.
- `Node::publish_announcement` refuses to run unless the default posting
  id equals the anchor constant — accidental use on client installs
  fails loud.

Wire / receive:
- `control::receive_post` verifies announcement signatures upfront
  alongside Control and Profile. Same pattern; same guarantees.

CLI one-shots (no daemon):
- `itsgoin <data_dir> --print-identity` — prints network_id +
  default_posting_id, exits.
- `itsgoin <data_dir> --announce --ann-category release
  --ann-channel stable --ann-version X --ann-title ... --ann-body ...
  --ann-url https://itsgoin.com/download.html` — builds + stores +
  propagates the signed post, exits.

deploy.sh:
- Now runs the announce one-shot inside the anchor-restart window
  (after binary swap, before start). The DB is free during that gap,
  so the one-shot can write without conflicting with the running
  daemon. The restarted daemon loads all storage on boot and serves
  the new announcement to pulling peers.

Tauri IPC:
- `check_release_announcement(channel)` → Option<ReleaseAnnouncementDto>
  — returns None when up-to-date.
- `get_update_channel` / `set_update_channel(channel)` — persists in
  settings kv key `ui_update_channel`; defaults to stable.
- `open_url_external(url)` — desktop-only (xdg-open / open / cmd start);
  refuses non-http(s) URLs. Android needs the opener plugin — TODO.

Frontend:
- Upgrade banner on the welcome screen, populated by
  `loadUpgradeBanner()`. Hidden when no newer release is known.
- Settings → Updates section with Stable/Beta radio + Check-now button
  + current status line.

Tests: announcement signature roundtrip; non-anchor author rejection;
non-announcement intent is a no-op. 124 / 124 core tests pass.
2026-04-23 01:50:12 -04:00
Scott Reimers
7e1e1dd738 Platform: Reset wipe, empty name, Android browse + backup-off, import as personas
Reset All Data:
- Sentinel now written at the app-level data_dir instead of the
  active identity's subdir. On Android the subdir path was never
  checked at startup, so reset silently did nothing.
- On detection, wipe EVERYTHING under the app data_dir: identity.key,
  itsgoin.db + WAL + SHM, blobs, all identity subdirs. Next launch
  is truly fresh — new network key, new posting key, no prior data.

First-run name:
- Display name is optional. Blank submits as anonymous.
- First-run modal + profile overlay placeholder updated to say
  "Display name (optional)".

Android file picker:
- pick_file on Android now uses tauri-plugin-android-fs'
  show_open_file_dialog (Storage Access Framework OPEN_DOCUMENT).
  Read the picked URI's bytes, stage them in the app's private cache
  as a timestamped file, return the staged path so existing
  import_* code can read it as a regular filesystem path.
- Zip filter passes application/zip + application/octet-stream (some
  file providers report the latter for .zip).

Android auto-backup off:
- AndroidManifest: allowBackup="false", fullBackupContent="false",
  dataExtractionRules pointing at new data_extraction_rules.xml
- New data_extraction_rules.xml excludes all domains from both
  cloud-backup and device-transfer. Prior default (allowBackup=true)
  silently replicated identity.key to Google Drive for any user with
  cloud backup on — which effectively published the root secret to
  a third party without asking. Users who want off-device backup use
  Settings -> Export (explicit zip they control).

Import as personas:
- New import_as_personas function in core/import.rs + new
  import_as_personas_cmd Tauri IPC.
- Reads identity.key from the bundle and adds it to posting_identities
  as a persona. Also reads posting_identities.json (v0.6+ bundles)
  and adds each entry. Dedupes by node_id.
- Posts stay AS-AUTHORED — original post_id, original author,
  original signatures, original wrapped_key recipients. No
  re-encryption. Content encrypted to any of the imported keys
  becomes decryptable because we now hold the secrets.
- Blobs, follows, profiles copied across.
- If current device has <=1 posting identity (the fresh-install one)
  and the bundle brings more, auto-switch the default to the first
  imported persona. Covers first-run-then-import flow cleanly.

Import wizard UI:
- New default option: "Restore as personas" — posts keep original
  authors; source's keys become personas you can post as.
- Old "Merge with decryption key" retained as "Consolidate under
  current default persona (requires source key)" for the case where
  a user intentionally abandons a persona.
- "Public posts only" and "Add as separate identity" retained.

deploy.sh made executable (chmod +x tracked).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:40:21 -04:00
Scott Reimers
288b53ffb1 Feed pagination, duplicate identity detection, pkarr leak fix, Android SAF
Feed pagination:
- Cursor-based pagination: get_feed_page/get_all_posts_page (20 posts/page)
- Batched engagement queries (3 bulk SQL queries instead of 4 per post)
- IntersectionObserver for infinite scroll (sentinel at midpoint)
- Viewport-based media loading (blobs only load when post enters view)
- Pre-fetch next page immediately after current page renders

Duplicate identity detection:
- Anchor detects when a NodeId is already mesh-connected during initial
  exchange and sets duplicate_active flag in response
- Client skips sync tasks when duplicate detected
- Frontend shows red warning banner

Privacy:
- Fixed pkarr leak: clear_address_lookup() removes default dns.iroh.link
  publishing. Only mDNS (local network) discovery enabled.

Android:
- SAF integration via tauri-plugin-android-fs: exports open native "Save As"
  dialog so users can save to Downloads/Drive/etc.
- Download/export paths use app data dir on Android (writable)
- File picker gated behind desktop cfg (blocking_pick not on Android)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 15:35:23 -04:00
Scott Reimers
cba30a1bb3 AppImage video fix, proper import posts, first-run chooser, file pickers
- bundleMediaFramework: true — bundles full GStreamer plugin set in AppImage.
  Fixes WebKit hang on video/audio (missing appsink/autoaudiosink plugins).
  MSDK/VA plugins removed post-build to avoid Ubuntu DMA assertion crash.
- Import creates complete posts: BlobHeader, VisibilityIntent, pinned blobs,
  self-follow. Imported posts now indistinguishable from locally created ones.
- First-run chooser: Start Fresh or Import Identity on fresh install only.
  Profile setup shown for existing identities without display name.
- File pickers: native Browse buttons on export (folder) and import (ZIP)
  via tauri-plugin-dialog.
- Export path: relative paths resolved against home dir.
- Lightbox close: only on overlay/image click, not inner form content.
- Growth loop skips self as N2 candidate.
- Node shutdown on identity switch (prevents zombie background tasks).
- media-src CSP includes asset protocol.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 13:49:52 -04:00
Scott Reimers
3cc39590a7 Design doc audit: update badges, fix outdated descriptions, add CDN/replication docs
Badge updates:
- BlobHeader: Planned → Complete (has receipt/comment slots, reactions, policy)
- LAN Discovery: Planned → Complete (iroh mDNS integration)
- UPnP TCP: Planned → Complete (both UDP+TCP renewal cycles)
- HTTP Post Delivery: added Complete badge

Description fixes:
- Share links: removed hostlist encoding, added tiered serving (redirect → punch → proxy)
- Eviction formula: added share_boost factor (+100 for 3+ downstream)
- Message types table: added ReplicationRequest/Response (0xE1/0xE2), count 41 → 49
- Engagement: added tombstone propagation description

New sections:
- Device roles & bandwidth budgets (Intermittent/Available/Persistent)
- Active CDN replication (10-min cycle, target prioritization, graceful degradation)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 00:20:47 -04:00
Scott Reimers
0abc244ee9 v0.3.4: Comment edit/delete, native notifications, forward-compatible protocol, UI fixes
Comment edit & delete:
- EditComment/DeleteComment BlobHeaderDiffOps with upstream+downstream propagation
- Trust-based: comment author can edit/delete, post author can delete
- Storage: edit_comment(), delete_comment() methods
- Frontend: inline edit (Enter/Escape), delete with confirm

Native notifications:
- tauri-plugin-notification for system notifications on all platforms
- Triggers for messages, new posts, reactions, and comments
- notif_reacts setting added, button-group toggles replace dropdowns
- _notifReady flag prevents startup spam

Protocol hardening:
- BlobHeaderDiffOp::Unknown variant with #[serde(other)] for forward compatibility
- Old nodes silently skip unknown ops instead of crashing

UI fixes:
- Self removed from Following list
- Offline follows in lightbox popup (auto-show if no one online)
- Sent DMs filtered from My Posts
- Comment threading scoped to closest .post (fixes duplicate ID issue)
- Select dropdown text legible in WebKitGTK (black on white options)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:47:53 -04:00
Scott Reimers
800388cda4 ItsGoin v0.3.2 — Decentralized social media network
No central server, user-owned data, reverse-chronological feed.
Rust core + Tauri desktop + Android app + plain HTML/CSS/JS frontend.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 20:23:09 -04:00