feat: ssh device suite#21
Merged
Merged
Conversation
- ISshSession/ISshShell/ISshSessionFactory + SshEndpoint in Core (no deps) - SSH.NET 2025.1.0 impl: exec/list/scp/shell, host-key TOFU via secrets store - busybox ls -la parser + root-delete guard (+unit tests) - 13.2 "Open web": library button -> LaunchUriAsync, Camera.WebInterfaceUrl
- migration 008: SshPort column (NULL = 22)
- SSH login/password in secrets store under cam:{id}:ssh:* (separate from RTSP/ONVIF)
- CameraDirectoryService.GetSshEndpointAsync: SSH creds or fall back to main
- SSH section in camera editor (user/password/port, optional) + validation
- IMajesticSshConfigClient + impl: cat read, scp+mv write, killall -HUP reload - SingleCameraPage "Edit via SSH" button (advanced opt-in) -> raw editor -> write+restart - fallback transport for when the HTTP Majestic API is disabled
- basic VT/ANSI emulator in Core (CSI moves, SGR colors, scroll, UTF-8) + tests - TerminalView control: grid render + keyboard -> shell bytes - SshTerminalViewModel over ISshShell; non-modal window on desktop, overlay on mobile - "SSH" button in the camera library row
- FileManagerViewModel: browse remote FS, download/upload with progress, mkdir, delete (root-guard + confirm) - cross-platform: remote panel + OS file pickers for local I/O (no local panel, avoids mobile sandbox) - ISshSession.CreateDirectoryAsync; RemotePath helpers (+tests); reusable PromptDialog for folder name - "Files" button in the camera library row; window on desktop, overlay on mobile
- new OpenIPC.Viewer.Infrastructure.Tests project - round-trip exec/list/upload/download/mkdir/delete against a real sshd (SkippableFact) - tools/sshd/docker-compose.yml + SshdFixture; skips when the container is down
- AndroidIPInterfaceProperties.GatewayAddresses throws PlatformNotSupported, killing the app at startup via SettingsPageViewModel ctor -> NIC selector - catch it and treat the NIC as gateway-less when unsupported
- Settings -> SSH: strict host-key toggle, default port, terminal font size, majestic.yaml path, "forget all host keys" - move host-key TOFU from the secrets store to JsonFileHostKeyStore (ISshHostKeyStore) so reset is one op - strict-off accepts and re-pins a changed key (reflashed camera); wired via IUserSettingsAccessor - TerminalView honors the configured font size
- OverlayDialogPresenter gains a fullScreen mode (fills TopLevel, no sheet card / scroll wrapper) - terminal & file manager use it on mobile; safe-area top inset so the title clears the status bar - lower content MinWidth/MinHeight so they fit narrow phones
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds direct device management over SSH for OpenIPC cameras:
an interactive terminal, an SCP file manager, "open web interface", and an
SSH transport for the Majestic config. All cross-platform (Win / Lin / Mac /
Android / iOS) — desktop opens windows, mobile uses full-screen overlays, and
local file I/O goes through
StorageProviderpickers (no sandbox issues).ISshSession/ISshShell/ISshSessionFactory+SshEndpointin Core (no package deps). Implemented inInfrastructure on SSH.NET 2025.1.0: connect (password / private key),
exec,directory listing via
ls -la, SCP upload/download with progress, delete,mkdir, interactive shell. Host keys are pinned on first use (TOFU) via the
secrets store; a changed key is refused.
http://{host}[:port]throughthe platform launcher.
008addsSshPort(NULL =22); SSH login/password live in the secrets store under
cam:{id}:ssh:*,separate from the RTSP/ONVIF login, with fallback to the main login.
MajesticSshConfigClientreads/etc/majestic.yaml(cat), writes it atomically (SCP +mv) and reloads(
killall -HUP majestic). Surfaced via "Edit via SSH" on the camera page —a fallback for when the HTTP API is disabled.
moves, SGR colors, scroll, UTF-8 reassembly), a
TerminalViewcontrol(grid render + keyboard → shell bytes), and
SshTerminalViewModel.(progress), mkdir, delete with confirm. Root-level deletes are refused
(
RemotePathGuard).Architecture
(
SshNetSessionFactory). ViewModels stay unit-testable.Testing
ls -laparser, root-delete guard,RemotePathhelpers,VT emulator (control codes, SGR, scroll, partial-UTF-8).
OpenIPC.Viewer.Infrastructure.Testsround-tripsexec/list/upload/download/mkdir/delete against a real sshd
(
tools/sshd/docker-compose.yml).SkippableFact— skips when the containeris down (e.g. Windows CI without Docker).
Related
Type
Checklist
TreatWarningsAsErrors=true).dotnet test); new Core logic has unit tests.AppreferencesCoreonly (Infrastructure / Video / Devices wired via DI in a head).Platforms tested
Screenshots / notes