The Tauri frame-src is an enumerated allowlist (unlike the permissive web CSP
`frame-src 'self' https:`), so embeds whose host isn't listed render as a
blank box in the desktop app with no visible error. Adds the two new music
providers (www.mixcloud.com, widget.deezer.com) and store.steampowered.com,
whose Steam widget shipped earlier but was already blank on desktop.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Taskbar showed two icons because the AppUserModelID was (a) set too late — after
the main window was built, so its taskbar button grouped under a mismatched
implicit AUMID — and (b) valued 'LotusGuild.LotusChat', which differs from the
bundle identifier 'org.lotusguild.lotus-chat' that Tauri's NSIS installer stamps
on its shortcuts. Fix both: set the AUMID at the top of run() before the window
is built (new set_process_aumid, split out of ensure_app_user_model_id), and
align the constant to the bundle identifier so the running window and a pinned
installer shortcut group together.
Notification click didn't raise the window: add a focus_main_window command
(reuses show_main) for the web/service-worker path, and call show_main directly
in the rich-toast Activated body-click handler.
Note: existing users who pinned the old mis-grouped icon may need to re-pin once.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add platform.twitter.com (interactive tweet embed) and embed.music.apple.com
(Apple Music player) to the webview frame-src.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend webview frame-src for the newly-added inline media players: www.tiktok.com,
www.dailymotion.com, geo.dailymotion.com, streamable.com, player.twitch.tv,
clips.twitch.tv, open.spotify.com, w.soundcloud.com.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lotus Chat now plays YouTube/Vimeo links inline; the webview CSP frame-src was
'self' blob: openstreetmap only, which blocked the embed players. Add
youtube-nocookie.com, youtube.com, and player.vimeo.com.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Windows CI failed: PROPERTYKEY is not in Win32::UI::Shell::PropertiesSystem.
Use the ready-made PKEY_AppUserModel_ID constant from Win32::Storage::Enhanced
Storage (same module jumplist.rs uses for PKEY_Title, feature already enabled)
instead of hand-rolling the PROPERTYKEY — drops the GUID::from_u128 dependency.
Also simplify IPersistFile::Save's fremember arg (it's bool, not BOOL).
All windows-crate symbols now verified against windows-docs-rs (PKEY_AppUser
Model_ID / IPersistFile::Save / SetCurrentProcessExplicitAppUserModelID /
CreateToastNotifierWithId).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
on_open_url and the argv fallback can both forward the same launch matrix: URL
on cold start, navigating the room twice. forward_deeplink now drops a repeat of
the same URL within ~1s (plain std Mutex/Instant — no windows-crate surface).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The WinRT rich toast (reply box P5-41, click-to-open-room P5-35) was inert on
Windows: CreateToastNotifier needs the process under an AppUserModelID mapped to
a Start-Menu shortcut, and none was registered — so it errored and silently fell
back to the plain plugin toast.
New native/aumid.rs (Windows-only; no-op elsewhere), called first in
native::setup: (1) SetCurrentProcessExplicitAppUserModelID("LotusGuild.LotusChat"),
(2) install/refresh a Start-Menu "Lotus Chat.lnk" carrying PKEY_AppUserModel_ID,
reusing jumplist.rs's IShellLinkW + IPropertyStore + PROPVARIANT + IPersistFile
pattern (best-effort; failures logged + swallowed). toast.rs now binds the
notifier via CreateToastNotifierWithId(AUMID).
CI-compile-only (windows runner); runtime needs a Windows build to confirm the
toast shows a reply box + opens the room. windows-crate 0.61 symbol assumptions
(IPersistFile, SetCurrentProcessExplicitAppUserModelID, PROPERTYKEY,
GUID::from_u128, CreateToastNotifierWithId) validated by CI — all mirror existing
jumplist.rs usage where possible.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- D1 (HIGH): Linux no-sleep was completely non-functional — the zbus
ScreenSaver inhibit was bound to a function-local D-Bus connection dropped on
return, so the screensaver service auto-released it instantly. Keep a
long-lived Connection in managed state (InhibitState { conn, cookie }) so the
same connection holds Inhibit and issues UnInhibit; created once, reused.
- D3: tray "Do Not Disturb" desynced from the web manualDndAtom after any reload
(custom-chrome toggle / logout) — the atom is in-memory and reset while the
tray stayed checked. Added TrayDndState + a get_tray_dnd command so the web
hook re-hydrates the atom on mount.
- D5: install_update now calls app.restart() after a successful install so the
new version actually runs (Linux AppImage kept running the old binary; the UI
hung on "installing").
CI-compile-verified (windows + linux). Web-side wiring (get_tray_dnd query,
updater terminal state) landed on cinny:lotus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rounds out the native app on Linux (Windows features kept; macOS stays no-op):
- power.rs: no-sleep during calls on Linux via a zbus org.freedesktop.ScreenSaver
Inhibit/UnInhibit (cookie held in ScreenSaverInhibit managed state).
- set_badge_count: Linux launcher badge via the Unity
com.canonical.Unity.LauncherEntry.Update D-Bus signal (best-effort; app_uri
= cinny.desktop per Tauri's mainBinaryName naming).
- tauri-plugin-autostart registered (+ autostart:allow-enable/disable/is-enabled
capabilities); web toggles it from Settings.
- Tray "Do Not Disturb" CheckMenuItem → emits lotus-dnd-changed to the web,
which ORs it into the notification quiet-gate.
zbus 5 (Linux target dep; blocking-api default). CI-compile-verified
(windows+linux); reviewer confirmed no build-breakers. Runtime to check on
Linux: DND toggle polarity, badge .desktop id.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`app.security.__csp_notes` failed `tauri.conf.json` schema validation
("Additional properties are not allowed") on BOTH platforms before any
compile. JSON can't hold comments and Tauri forbids extra keys, so the
rationale lives here instead:
CSP rationale (audit 2026-07): tightened from the fully-open policy.
- 'unsafe-eval' MUST stay: the native→web bridge (forward_deeplink /
emit_to_web) uses window.eval, governed by page CSP; also covers crypto wasm.
- The sha256 hash allowlists the single inline `window.global ||= window;`
shim in cinny's index.html (~line 96). If that snippet or its indentation
changes, recompute the hash or the shim is silently blocked.
- connect-src / img-src / media-src keep http: (plain-http homeservers).
- Review-added: Google Fonts (VT323) + OpenStreetMap iframe (m.location).
- style-src keeps 'unsafe-inline' for React style attributes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Repairs the CI Windows compile (first build to reach the Rust after the web/
case-collision failures cleared): these two COM interfaces live in
windows::Win32::UI::Shell::Common (feature Win32_UI_Shell_Common), not
System::Com nor Shell. Added the feature; corrected the import.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
script-src drops unsafe-inline/blob/data/http/https (any-origin script exec is
gone); the single inline shim in index.html is hash-pinned; object-src 'none',
base-uri 'self'. Kept deliberately: 'unsafe-eval' (the window.eval native→web
bridge + crypto wasm), broad connect-src (arbitrary homeservers), http: in
img/media (plain-http homeservers), and review-added allowances for Google
Fonts (VT323) and the OpenStreetMap location iframe.
NEEDS RUNTIME SMOKE ON WINDOWS before release (CI can't catch CSP breakage):
boot, avatars/media, VT323 renders, location map embeds, calls connect, deep
links navigate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
From the deep-audit wave (reviewer-verified: capability identifiers valid, no
removed-crate references, GDI free ordering correct):
- Removed 8 never-registered plugins (clipboard-manager, fs, shell, http,
process, os, dialog, global-shortcut) from Cargo.toml AND their capability
grants (shell:allow-execute, unscoped fs writes, http:default, …) — verified
the web never invokes any of them. A latent RCE-class surface is gone.
- on_new_window: only http/https/mailto reach the OS opener (file:///custom
schemes previously bypassed the opener capability scope entirely).
- set_badge_count: freed hdc + hdc_screen on all three GDI error paths
(leaked per badge update in a long-running tray app).
- 8s reveal failsafe gated by an AtomicBool: no longer re-shows a window the
user closed to tray; page-load reveal now fires once only (logout reloads
don't re-surface a tray-hidden window); recovery for a missed page-load
event preserved.
- toast.rs: store pruned on Activated too + capped at 20 (was unbounded).
- Startup no longer panics when the bundled icon is missing (tray skipped
gracefully); msSmartScreenProtection no longer disabled (throttling
disables kept); rust-version corrected to 1.77.2.
- release.yml update-manifest: fails on empty signatures (was: could publish
a manifest that traps Windows users in a failed-update loop); partial-
failure window documented. Deleted the stale upstream tauri.yml workflow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Four unresolved-import/type errors from the release build (first real compile):
- toast.rs: generic IMap moved to the windows-collections crate; read the reply
from the ValueSet returned by UserInput() directly (HasKey/Lookup are exposed
on the class).
- jumplist.rs: PROPVARIANT lives in Win32::System::Com::StructuredStorage (not
windows::core); IObjectArray/IObjectCollection in Win32::System::Com (not
UI::Shell); PKEY_Title in Win32::Storage::EnhancedStorage (feature added);
build the title PROPVARIANT via From<&str> (VT_LPWSTR).
- smtc.rs: event registrations return a plain i64 token in windows 0.61 (the
EventRegistrationToken newtype is gone).
- thumbbar.rs: HICON was imported inside the fn body but used in its signature —
fully qualify the return type.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause: lib.rs applies a Mica backdrop to the main window at startup;
set_custom_chrome then stripped the frame with set_decorations(false), and
Mica + frameless is a broken combination on Windows (DWM backdrop glitches
the whole surface).
- set_custom_chrome: clear_mica() before undecorating, re-apply_mica() when
restoring the native frame; set_shadow(true) so the frameless window keeps
its drop shadow + resize borders.
- window-state plugin: exclude StateFlags::DECORATIONS — the chrome toggle
owns the decorated flag; restoring a saved decorated=false at startup would
recreate the Mica-on-frameless glitch before the web side loads.
Pairs with the web-side TitleBar drag fix (explicit window_start_drag on
mousedown instead of data-tauri-drag-region) in the cinny repo.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add WebView2 additional_browser_args to disable Chromium background throttling
(--disable-background-timer-throttling / -renderer-backgrounding /
-backgrounding-occluded-windows) so the existing JS Matrix /sync loop and
notifications keep running full-speed when the app is closed to the tray, instead
of standing up a second headless Rust sync client. Tauri's default WebView2 args
are preserved (setting this overrides them). Windows/WebView2 only; does not block
system sleep (that's P5-46, calls-only). CI Windows compile pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- toast.rs: Windows.UI.Notifications rich toast (reply input + Send action);
in-process Activated event → emit lotus-notification-activate {path} (click) /
lotus-notification-reply {roomId,text}. Falls back to tauri-plugin-notification
(WinRT error / non-Windows). The NOTIFICATION_BRIDGE now routes notifications
carrying a roomId (tag) to show_rich_toast. Features: UI_Notifications,
Data_Xml_Dom, Foundation_Collections.
- focus_assist.rs: SHQueryUserNotificationState poll thread → emit
focus-assist-changed {active} on QUNS_QUIET_TIME/PRESENTATION/D3D_FULLSCREEN/BUSY.
No new Cargo features.
CI Windows compile pending (no local Rust toolchain). Runtime caveat: WinRT toasts
need a Start-menu shortcut + matching AppUserModelID (org.lotusguild.lotus-chat);
without it CreateToastNotifier errors and the code falls back to the plugin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a `native/` module system (each feature = its own module exposing
`#[tauri::command]`s + optional `setup`; `emit_to_web` pushes DOM CustomEvents to
the web like `forward_deeplink`). Wired into generate_handler! + native::setup;
windows-crate feature union added to Cargo.toml.
- power.rs (P5-46): SetThreadExecutionState held on the main thread while a call
is active; released on end. Cross-platform (no-op off Windows).
- jumplist.rs (P5-36): ICustomDestinationList "Recent Rooms" of IShellLink tasks
launching the exe with a matrix: arg (existing deep-link handler opens the room).
- thumbbar.rs (P5-44): ITaskbarList3 ThumbBar Mute/Deafen/End (GDI HICONs) + a
window subclass catching THBN_CLICKED → emit thumbbar-action.
- smtc.rs (P5-43): WinRT SystemMediaTransportControls via GetForWindow; ButtonPressed
→ smtc-action; call-state command. (Experimental for a non-media app.)
- network.rs (P5-49): INetworkListManager poll thread → emit network-changed.
- chrome.rs (P5-47): cross-platform window-control commands + set_custom_chrome
(set_decorations) for the opt-in TDS titlebar.
NOT compile-verified locally (no Rust/Windows toolchain on the dev box) — this is
for the CI Windows compile pass (GitHub test.yml / Gitea windows runner). Expect a
possible fixup round (windows-crate feature/namespace paths, e.g. subclass APIs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The injected notification bridge defined `permission` as a getter-only property.
When the notification plugin / a polyfill assigned `Notification.permission`, it
threw "Cannot set property permission of function TauriNotification ... which has
only a getter" at page load. Add a no-op setter so it still reads 'granted' but
assignment can't crash.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CreateDIBSection does not guarantee zeroed memory. Uninitialized bytes
with non-zero RGB but zero alpha were getting alpha=255 set by the
existing pixel loop, causing a black square around the badge circle.
Zeroing with write_bytes before GDI drawing ensures only explicitly
painted pixels are opaque.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Windows overlay badge rendered as a black square because GDI drawing
functions do not write the alpha channel — all pixels stay at A=0, causing
Windows to fall back to the opaque monochrome mask and draw corner pixels
as solid black.
Fix: after all GDI calls, iterate the pixel buffer and set alpha=0xFF for
every non-zero pixel; corner pixels (zero) retain A=0 and composite as
transparent, giving a proper circular badge.
Also increased bitmap size 16→20 and font height 11→14 for better
legibility, especially for two-digit mention counts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- set_tray_unread command re-renders the tray icon with a red unread dot
composited onto the base icon (handle + base pixels kept in managed state).
- flash_window command flashes the taskbar via request_user_attention.
- Register both commands; bump cinny submodule to 107921e0 (web wiring).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tauri::tray is gated behind the 'tray-icon' Cargo feature; the tray code
failed to compile without it (E0432). Also enable image-png for tray icon
decoding.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- System tray with Open/Quit menu + left-click toggle; closing the window now
minimizes to tray instead of quitting, so notifications keep arriving.
- Single-instance: a second launch focuses the running window (and forwards a
matrix: link) instead of colliding on the localhost port.
- Window: 1100x720 default, 480x600 min, centered first run; starts hidden and
shows on page-load to kill the white launch flash (8s failsafe).
- matrix: deep links via tauri-plugin-deep-link -> dispatched to the web client
(useDeepLinkNavigate) for both cold-start and already-running cases.
- Windows 11 Mica backdrop (subtle; app paints opaque TDS bg).
- NSIS installer: per-user install (no UAC), downloadBootstrapper.
- Remove dead/broken src/menu.rs.
- Bump cinny submodule to 053b364a (deep-link web handler).
Note: Rust not compiled locally (no toolchain / Windows-only paths); verified by
careful API review against tauri 2.10 — needs a real 'tauri build' to confirm.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regenerated all desktop icons (32/128/128@2x PNG, multi-res icon.ico [16-256],
icon.icns, Windows Store Square*/StoreLogo) from a genuinely transparent
1024x1024 Lotus source via 'tauri icon'. The old icons had a black square
background that looked wrong on the Windows taskbar; these have an alpha
background so only the lotus + dove show.
Also bumps the cinny submodule to 3282832a (corrected transparent source asset).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Windows (windows-rs 0.61):
- FONT_PITCH_AND_FAMILY does not exist; ipitchandfamily is u32 - revert
to (DEFAULT_PITCH.0 | FF_DONTCARE.0) as u32
- CreateBitmap returns HBITMAP directly (not Result<HBITMAP>); replace
.map_err()? with explicit null pointer check on hbm_mask.0
Linux AppImage:
- Shell script wrapper is destroyed by Tauri's `dd if=/dev/zero bs=1
count=3 seek=8` which zeroes the shebang at bytes 8-10
- Compile a tiny C ELF forwarder instead: ELF bytes 8-10 are
EI_OSABI/EI_ABIVERSION padding (already zero), dd is a no-op
- Use page-aligned squashfs offset search for more reliable extraction
- Add set -e to Stage step and explicit gcc install
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move BOOL import to windows::core (removed from Win32::Foundation in 0.61)
- Move CreateBitmap import from WindowsAndMessaging to Win32::Graphics::Gdi
- Wrap nullable handles in Some() for GetDC, CreateCompatibleDC,
CreateDIBSection, ReleaseDC (new Option<T> API in 0.61)
- Add .into() for all SelectObject/DeleteObject GDI handle args (now HGDIOBJ)
- Use FONT_PITCH_AND_FAMILY type directly in CreateFontW instead of u32 cast
- Make DrawTextW slice mutable (&mut [u16] required in 0.61)
- Use hicon.unwrap_or_default() for SetOverlayIcon (takes HICON not Option<HICON>)
- Add libfuse2 to apt-get for Linux AppImage bundler (FUSE mount fallback)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Windows: ConvertTo-Json outputs True/False (invalid JSON) and UTF-16
BOM, corrupting tauri.conf.json. Switch to `node -e` which round-trips
JSON correctly.
Linux: linuxdeploy is itself an AppImage and cannot execute inside
Docker without FUSE. APPIMAGE_EXTRACT_AND_RUN=1 makes it self-extract
and run as a plain binary instead.
Also fix unreachable_code warning in check_for_update.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tauri's generate_context! macro requires RGBA PNG icons. All 14 files
were RGB (source logo is RGB); converted with Pillow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Register tauri-plugin-notification; inject initialization script that
patches window.Notification to route through the native plugin and
always report permission as granted — bypasses WebView2's default deny
- Also grant COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS via existing
PermissionRequestedEventHandler
- Register tauri-plugin-updater; add check_for_update and install_update
commands using the pubkey/endpoint already in tauri.conf.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds set_badge_count Tauri command (Windows only). Uses CoCreateInstance
to get ITaskbarList3 and SetOverlayIcon to display a dynamically drawn
badge on the taskbar button. The badge is a 16x16 GDI bitmap: red circle,
white bold Segoe UI text, capped at "99+". Passing count=0 clears the
overlay. Uses windows = 0.61 (already a transitive dep via webview2-com).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updates all Tauri icon targets: 32x32, 128x128, 128x128@2x, icon.png,
icon.ico (multi-size), icon.icns (16/32/128/256/512), and all Windows
NSIS Square*Logo and StoreLogo sizes. Generated from lotus_chat.png
(1254x1254 source in the cinny repo).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add prepare job: computes version (4.12.{run_number}), creates/updates
the Gitea release once — eliminates the race condition where build-windows
and build-linux both tried to create the same release simultaneously.
- Auto-increment version: both build jobs patch tauri.conf.json with
4.12.{run_number} before building, so every CI run produces a strictly
increasing semver and the Tauri updater fires correctly.
- Fix double -- in Windows build command: was 'build -- --bundles nsis'
which passed --bundles as cargo args (silently ignored), causing all
bundle targets to build. Now 'build --bundles nsis' (single --).
- Add setup-node to Windows build: pins Node.js to .node-version like
the Linux job already does.
- update-manifest: uses version/release_id from prepare outputs instead
of re-fetching and parsing the release name.
- Fix window title: was "Cinny", now "Lotus Chat".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
with_webview is on WebviewWindow (the built window), not WebviewWindowBuilder.
Also import COREWEBVIEW2_PERMISSION_KIND as a type for the out-param zero-init.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix COREWEBVIEW2_PERMISSION_KIND out-param pattern in PermissionRequestedEventHandler
- Add "wry" feature to tauri dep so with_webview compiles on Windows
- Build both appimage and deb on Linux for auto-update compatibility
- Commit AppRun-x86_64 binary to avoid GitHub download timeout in CI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous approach used windows::core::implement to manually implement
ICoreWebView2PermissionRequestedEventHandler_Impl, but the sealed
IUnknownImpl constraint in webview2-com prevents external #[implement]
usage — you must use the crate's own pre-built handler types.
Replace with PermissionRequestedEventHandler::create() which wraps the
closure and handles COM ref-counting internally. Also removes the now-
unused windows = "0.61" direct dependency.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
with_webview is not available on Linux; break the builder chain and apply
it conditionally so the Linux build compiles without the wry feature flag.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WebView2 silently denies getUserMedia() unless a PermissionRequested
handler explicitly allows it. macOS was already covered by Info.plist;
Windows had nothing. Adds a COM event handler via with_webview that
auto-approves mic and camera requests so Element Call voice/video
works in the desktop app.
Also includes previously uncommitted changes:
- tauri.conf.json: add media-src / mediastream: to CSP
- Info.plist: macOS NSMicrophoneUsageDescription / NSCameraUsageDescription
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: update CSP to allow reordering rooms inside space
Fixes https://github.com/cinnyapp/cinny/issues/2949
* disable native dnd in windows configuration
* Disable drag and drop for main webview window in lib.rs
* Remove dragDropEnabled setting from tauri.conf.json
* Replace drag_drop_enabled with disable_drag_drop_handler
* fix: enable tauri plugin opener
* fix: add remote urls to make build work on Windows
* fix: update Cargo.lock
We need tauri v2.8.0 since which supports `WebviewBuilder::on_new_window`
* fix: handle `window.open()` using `WebviewBuilder::on_new_window`
---------
Co-authored-by: Krishan <33421343+kfiven@users.noreply.github.com>