Skip to content

Desktop: Support local and remote server #1490

@lreading

Description

@lreading

Describe what problem your feature request solves:

Currently, the Desktop app runs as a standalone electron app with only the front-end code. The front-end is designed in a way where it does not need the express server to function. This paradigm introduces friction when developing features: we often make the distinction of "this is web only", as there are sometimes pieces that need to run in a server context.

There are some existing issues (like #883) that are requesting feature parity between desktop and web. This issue proposes to bring the web and desktop versions closer to feature parity iteratively, through many child issues.

Describe the solution you'd like:

Introduce the concept of an optional server to the electron app. This needs to remain optional, and disabled by default. This shift would effectively change the threat model/trust boundaries of the desktop app. Traditionally, Threat Dragon Desktop has been a thin client for the frontend, and is 100% local (with the exception of a couple of CDN resources). With this change, we can eventually achieve feature parity between the web/desktop versions of Threat Dragon, and enables easier development of features such as #1190 - which could cover both desktop and web at the same time.

This project would include a very large amount of code changes, so it would be important to break this down into discrete tasks. The pull requests The guiding principles of these changes include:

  • Disabled by default / opt-in only
  • When the feature is enabled, use sensible and secure defaults, allow for easy and persistent configuration
  • Backwards compatibility - no breaking changes - this should require a minor version bump only
  • Secure by design

I will not create the associated child issues until we've had a chance to discuss. The child issues would include:

Desktop configuration editor
  • Create a standard desktop config that is saved in the userData path using Electron's safeStorage, probably in JSON format
    • Using a different storage mechanism to differentiate between secrets and config is a valid option - but we risk missing a sensitive field. I think it's safer to treat the entire config file as a secret
  • Add a way to edit the config file from the desktop app (text editor w/ validation and errors)
  • Keep this gated behind a feature flag (env var) that defaults to off
  • Publish JSON schema
  • Ensure upgrades/updates do not clobber existing config
Remote server URL configuration

Rather than jumping straight into bundling and running the server code, a sensible first step could be allowing the configuration to specify a remote server URL. If configured, the desktop app can use the remote URL as a backend. This could resolve issues such as #883

  • Use previous issue's configuration / editor to allow for a remoteServerUrl value
  • Configure frontend to use the remoteServerUrl if in electron and enabled
  • Only allow HTTPS or localhost (127.0.0.1, 0.0.0.0, localhost)
  • If not localhost, reject invalid certifications
  • Potentially add another config value to allow non-https, but flag it as dangerous: DANGEROUS_ALLOW_UNTRUSTED_CERTS
Bundle server code in Electron

This would be strictly for electron build/bundling config. The only goal would be to start shipping the server code, but not running it yet.

  • Test all target packaging (windows, macos, appimage, snap, deb, rpm, etc). Electron's bundling can vary slightly between targets
  • We may need to run something like https://github.com/electron/rebuild to make sure that dependencies are built using the correct runtime version of NodeJs
Server startup API & health check from desktop

Same as before, this will be disabled by default. The goal is to run the server locally, but only on-demand. This should not start the server based on configuration.

  • Create UI (feature flagged) to allow server start/stop/reload
  • Ensure configuration is easy and applies sane defaults for the local server
  • The server binds to 127.0.0.1 and uses a random port
  • The frontend communicates with the running server
  • Add a UI for viewing server logs
  • Add a UI for server start/stop/restart commands
  • Auto-restart server on config change
  • Allow for full server configuration: ENV vars can be provided via desktop configuration file
Per-session shared key auth

In order to prevent other applications from making unauthorized changes through the server, we should implement a per-session shared secret as an authorization boundary. I'm intentionally approaching the "overkill" territory for this as a starting point. It would be perfectly reasonable to create a token during install/upgrade, and save that in electron's safeStorage. But to start, especially given that running a local server is a new concept for Threat Dragon, I think per-session token generation is the safest. This should be easy to rollback if there's community interest in external integrations with the local server running in the desktop client.

  • Modify server to allow for configurable shared secret auth (could be hmac, could just be a user-defined token, TBD)
  • Token must be provided to both the server and frontend
  • Token should only be valid for a single server launch
  • Token rotates on every server start/refresh
Conditionally start server at launch

If there is a saved configuration and it is set up to start the server on launch, we should start the server.

  • Always fall back to "local only" (default) mode
Documentation, e2e testing, and polish

This will require a lot of documentation. We should strive to keep the docs up to date with each issue. After the functional issues are complete, we can revisit documentation and also apply e2e tests. We are already pretty light on e2e tests (#1275), so adding a solid baseline of e2e tests covering the local/remote server feature would be fantastic.

  • Re-test all build targets. Special focus on snap and AppImage packaging, as there are some interesting sandboxing corners
  • Ensure documentation is complete, easy to read, and has examples/screenshots
  • Complete configuration, including JSON schema is documented
  • Document shortcomings and workarounds for Electron's safeStorage (linux, also snap)
  • Ensure configuration errors point to the correct documentation
  • Consider including a threat model for the updated desktop client in the bundled examples
  • Remove feature flags, enable configuration edit by default. Local / remote server configuration is still disabled by default, but the UI can be visible by default

Security considerations:

  • Electron's safeStorage has limitations, especially on Linux. Prevent saving an unencrypted version of the file, provide guidance on how to configure safeStorage in snap packaging and on unsupported linux configurations
  • Encrypted configuration files should have sane ownership and permissions
  • Treat all configuration as sensitive to avoid misses with specific values
  • Local servers must use 127.0.01 (as opposed to system IP or 0.0.0.0)
  • Local server must use a random port to avoid contention
  • Local server must expose server logs for traceability and auditability
  • Local server must use a unique, per-session auth token to ensure other apps/code cannot communicate with the server
  • Explore local-only CORS configuration (could we accept only file:// protocols and local origins when shared secret auth is configured?
  • Always fallback / failover to existing "local only" mode

Declaration:

By submitting this issue you have:

Additional context:

If this is desirable, I will break down the tasks into child issues and track as appropriate. I wanted to have a discussion first to ensure there is not significant pushback from the community, as this does materially change the threat model for the desktop client.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions