Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,19 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
go-version: '1.24'

- name: Install Linux dependencies
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm'
run: |
sudo apt-get update
sudo apt-get install -y gcc libgl1-mesa-dev xorg-dev

- name: Test
env:
CGO_ENABLED: 1
run: go test ./...

- name: Build (Windows)
if: matrix.os == 'windows-latest'
env:
Expand Down
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **Bitwarden integration**: connection passwords can be stored as `bw://<item-id>`
references and are resolved through the Bitwarden CLI at connect time. Works
with bitwarden.com, self-hosted Bitwarden and Vaultwarden.
See [docs/BITWARDEN-SETUP.md](docs/BITWARDEN-SETUP.md).
- Optional field selector on references: `bw://<item-id>/username`, `/totp`,
`/notes`; the password is the default.
- **Bitwarden item picker** in the add and edit connection dialogs, with search
and a vault sync button, plus a "Store password in Bitwarden" option that
creates a login item and replaces the password with its reference.
- Secret provider abstraction (`secrets.Provider`, `secrets.Registry`), so the
configuration manager, launcher and GUI no longer depend on a single password
manager.
- Unit tests for the secret providers, reference parsing and the encryption
helper, plus a `go test ./...` step in CI.

### Changed
- The 1Password authentication warning at start-up is now a generic secret
provider check, runs off the UI goroutine, and only asks about providers that
the configuration actually references.

### Security
- The `bw serve` helper process is bound to loopback on a random port, started
only when a Bitwarden reference is used, and terminated on exit. It is also
placed in a Windows job object, and given a parent death signal on Linux, so
it does not survive a crash.
- Passwords are no longer passed on a command line, where any local process
could read them out of the process list:
- SSH on Windows uses PuTTY `-pwfile` with a private temporary file that is
deleted as soon as PuTTY has started, instead of `-pw`.
- SSH on Linux and macOS passes the password to `sshpass` through the
`SSHPASS` environment variable instead of `-p`; the temporary file is
removed by the generated snippet before `ssh` starts.
- RDP credentials are written to the Windows Credential Manager through the
API instead of `cmdkey /pass:`.

### Known limitations
- On Linux, `xfreerdp` is still invoked with `/p:<password>`.

## [1.0.4] - 2026-01-28

### Fixed
Expand Down
32 changes: 21 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
# MremoteGO

> A modern, cross-platform remote connection manager with git-friendly YAML configs and 1Password integration.
> A modern, cross-platform remote connection manager with git-friendly YAML configs and 1Password and Bitwarden integration.

[![Go Version](https://img.shields.io/badge/Go-1.23+-00ADD8?style=flat&logo=go)](https://go.dev/)
[![Go Version](https://img.shields.io/badge/Go-1.24+-00ADD8?style=flat&logo=go)](https://go.dev/)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey)](https://github.com/jaydenthorup/mremotego)

## Why MremoteGO?

**The Problem**: mRemoteNG uses XML configs that are painful to diff, merge, and share with teams. Passwords are awkwardly encrypted per-machine.

**The Solution**: MremoteGO uses clean YAML configs that work beautifully with git, plus optional 1Password integration for secure team password sharing.
**The Solution**: MremoteGO uses clean YAML configs that work beautifully with git, plus optional 1Password and Bitwarden integration for secure team password sharing.

## ✨ Features

- 🎨 **Modern GUI** - Clean interface with connection tree, search, and quick actions
- 🔐 **Password Encryption** - AES-256-GCM encryption at rest with master password
- 🔑 **1Password Integration** - Store passwords securely using `op://` references
- 🛡️ **Bitwarden Integration** - Store passwords in Bitwarden or Vaultwarden using `bw://` references
- 📝 **Git-Friendly** - YAML configs are easy to diff, merge, and review
- 🖥️ **Cross-Platform** - Windows, Linux, macOS (AMD64 & ARM64)
- ⚡ **Fast** - Native GUI with instant connections
Expand Down Expand Up @@ -69,7 +70,7 @@ Simply run the executable without arguments:

1. Click **[+]** or press `Ctrl+N`
2. Fill in connection details (name, protocol, host, credentials)
3. Optionally push password to 1Password
3. Optionally pick a password from Bitwarden, or push it to 1Password or Bitwarden
4. Click **Save**

**Connecting:**
Expand Down Expand Up @@ -145,13 +146,14 @@ connections:
host: dev.example.com
port: 3389
username: developer
password: bw://8f3c1d9a-4e2b-4c77-9f10-1a2b3c4d5e6f # Bitwarden reference
```

## 🔐 Security

### Password Storage Options

MremoteGO supports three password storage methods:
MremoteGO supports four password storage methods:

1. **1Password Integration** (Recommended for teams):
- Store passwords securely in 1Password vaults
Expand All @@ -160,20 +162,27 @@ MremoteGO supports three password storage methods:
- Supports biometric unlock
- See [1Password Setup Guide](docs/1PASSWORD-SETUP.md)

2. **Encrypted** (Recommended for local use):
2. **Bitwarden Integration** (Recommended for teams):
- Store passwords in Bitwarden, self-hosted Bitwarden or Vaultwarden
- Use `bw://item-id` references in your config
- Safe to commit configs to git
- Pick items from the vault directly in the connection dialog
- See [Bitwarden Setup Guide](docs/BITWARDEN-SETUP.md)

3. **Encrypted** (Recommended for local use):
- AES-256-GCM encryption with PBKDF2 key derivation (100,000 iterations)
- Master password required on startup
- Passwords stored as `enc:base64(salt+nonce+ciphertext)`
- See [Encryption Guide](docs/ENCRYPTION.md)

3. **Plain Text** (Not recommended):
4. **Plain Text** (Not recommended):
- For testing or when other methods aren't suitable
- Should not be committed to git
- Use `.gitignore` to exclude `connections.yaml` and `config.yaml`

### Best Practices

- ✅ Use 1Password for team environments
- ✅ Use 1Password or Bitwarden for team environments
- ✅ Use encryption for personal configs
- ✅ Add `config.yaml` and `connections.yaml` to `.gitignore`
- ✅ Use separate configs for different environments
Expand All @@ -186,13 +195,14 @@ MremoteGO supports three password storage methods:
- **[GUI Guide](docs/GUI-GUIDE.md)** - Complete GUI reference
- **[Encryption Guide](docs/ENCRYPTION.md)** - Password encryption details
- **[1Password Setup](docs/1PASSWORD-SETUP.md)** - Secure password management
- **[Bitwarden Setup](docs/BITWARDEN-SETUP.md)** - Bitwarden and Vaultwarden integration
- **[Password Management](docs/PASSWORD-MANAGEMENT.md)** - Security best practices

## 🛠️ Development

### Prerequisites

- Go 1.23 or later
- Go 1.24 or later
- For Linux: `gcc`, `libgl1-mesa-dev`, `xorg-dev`
- For GUI builds: Fyne dependencies

Expand Down Expand Up @@ -224,7 +234,7 @@ mremotego/
│ ├── crypto/ # Encryption/decryption
│ ├── gui/ # Fyne GUI components
│ ├── launcher/ # Protocol launchers (SSH, RDP, etc.)
│ └── secrets/ # 1Password integration
│ └── secrets/ # Password manager providers (1Password, Bitwarden)
├── pkg/
│ └── models/ # Data models
└── docs/ # Documentation
Expand Down Expand Up @@ -299,7 +309,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
### 📋 Planned Features

#### Password Managers
- [ ] Bitwarden CLI integration (`bw://` references)
- [x] Bitwarden CLI integration (`bw://` references)
- [ ] LastPass CLI integration (`lpass://` references)
- [ ] HashiCorp Vault integration
- [ ] Pass (password-store) integration for Linux
Expand Down
6 changes: 6 additions & 0 deletions cmd/mremotego-gui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/jaydenthorup/mremotego/cmd/mremotego/cmd"
"github.com/jaydenthorup/mremotego/internal/config"
"github.com/jaydenthorup/mremotego/internal/gui"
"github.com/jaydenthorup/mremotego/internal/secrets"
)

func main() {
Expand All @@ -37,6 +38,11 @@ func runGUI() {
myApp := app.NewWithID("com.mremotego.app")
myApp.Settings().SetTheme(&customTheme{})

// Secret providers may run helper processes; make sure they are stopped
// however the application exits.
myApp.Lifecycle().SetOnStopped(secrets.Shutdown)
defer secrets.Shutdown()

// Set application icon (ignore errors - icon is optional)
if icon := gui.GetAppIcon(); icon != nil {
myApp.SetIcon(icon)
Expand Down
9 changes: 8 additions & 1 deletion cmd/mremotego/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/spf13/cobra"
"github.com/jaydenthorup/mremotego/internal/config"
"github.com/jaydenthorup/mremotego/internal/secrets"
)

var (
Expand All @@ -21,7 +22,13 @@ in a human-readable YAML format that works great with version control.`,

// Execute runs the root command
func Execute() {
if err := rootCmd.Execute(); err != nil {
err := rootCmd.Execute()

// Stop helper processes started by secret providers. This cannot be a
// defer because the error path calls os.Exit.
secrets.Shutdown()

if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
Expand Down
162 changes: 162 additions & 0 deletions docs/BITWARDEN-SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Bitwarden Setup Guide

MremoteGO can read connection passwords from Bitwarden, so that:

- Passwords never appear in your config files
- Configs stay safe to commit and share via git
- Credentials can be rotated in one place for the whole team

This works with bitwarden.com, self-hosted Bitwarden and Vaultwarden.

## How it works

Bitwarden has no library interface for other applications, so MremoteGO uses
the official Bitwarden CLI. On first use it starts `bw serve` as a hidden child
process bound to `127.0.0.1` on a random free port, reads what it needs over
that local API, and stops the process when MremoteGO exits.

MremoteGO never asks for, sees or stores your master password. The child
process inherits the `BW_SESSION` variable, so you unlock the vault once in
your terminal and every lookup after that is authorised by that session.

## Quick Setup

### 1. Install the Bitwarden CLI

```powershell
winget install Bitwarden.CLI
```

```bash
# macOS
brew install bitwarden-cli

# Linux
npm install -g @bitwarden/cli
```

Verify with `bw --version`.

### 2. Point the CLI at your server

Only needed for self-hosted Bitwarden or Vaultwarden:

```powershell
bw config server https://vault.example.com
```

### 3. Log in and unlock

```powershell
bw login
$env:BW_SESSION = bw unlock --raw
bw status # should report "unlocked"
```

```bash
bw login
export BW_SESSION="$(bw unlock --raw)"
bw status
```

### 4. Start MremoteGO from that same terminal

```powershell
.\mremotego.exe
```

The session key is inherited by MremoteGO and by the `bw serve` process it
starts. Launching MremoteGO from a desktop shortcut instead will leave the
vault locked, and it will show you these instructions.

## Using Bitwarden References

### In your config

Instead of a plain text password, store a reference to the vault item:

```yaml
connections:
- name: "Production Server"
protocol: ssh
host: prod.example.com
username: admin
password: bw://8f3c1d9a-4e2b-4c77-9f10-1a2b3c4d5e6f
```

Reference format:

| Reference | Resolves to |
|-----------|-------------|
| `bw://<item-id>` | the item's password |
| `bw://<item-id>/password` | the item's password |
| `bw://<item-id>/username` | the item's username |
| `bw://<item-id>/totp` | the current TOTP code |
| `bw://<item-id>/notes` | the item's notes |

References use the item id rather than its name, so renaming an item in
Bitwarden does not break your config.

### Finding an item id

**In the GUI:** click **Bitwarden...** next to the password field when adding
or editing a connection. Search your vault, pick an item, and the reference is
filled in for you along with the username.

**On the command line:**

```powershell
bw list items --search "production" | ConvertFrom-Json | Select-Object id, name
```

### Creating items from MremoteGO

1. Type the password into the password field as usual
2. Tick **Store password in Bitwarden**
3. Save

MremoteGO creates a login item named after the connection, with the username
and a URI of `<protocol>://<host>`, then replaces the password in your config
with the new `bw://` reference.

## Security notes

- **`bw serve` has no authentication of its own.** Anything running as your
user on your machine could talk to it while it is up. MremoteGO limits the
exposure by binding it to loopback on a random port, starting it only when a
Bitwarden reference is actually used, and terminating it on exit. On Windows
the process is placed in a job object and on Linux it gets a parent death
signal, so it also dies if MremoteGO crashes.
- **`BW_SESSION` unlocks your whole vault.** Treat it like a password: do not
put it in a script that others can read, and close the terminal when done.
- **References are not encrypted at rest**, on purpose. They contain no secret
material, and leaving them readable is what keeps configs diffable in git.
This matches how `op://` references are handled.

## Troubleshooting

**"Bitwarden CLI (bw) is not installed or not in PATH"**
Install the CLI and make sure `bw --version` works in the same terminal you
start MremoteGO from.

**"bitwarden vault is locked"**
The session key is missing or expired. Run `bw unlock --raw` again, set
`BW_SESSION`, and restart MremoteGO from that terminal.

**"not logged in to bitwarden"**
Run `bw login`. For a self-hosted server, run `bw config server <url>` first.

**An item you just created elsewhere is not in the picker**
The CLI serves items from a local cache. Click **Sync vault** in the picker, or
run `bw sync`.

**RDP connects but prompts for the password**
RDP is deliberately allowed to continue when a reference cannot be resolved, so
you still get a login prompt instead of an error. Check the vault state as
above.

## See also

- [Password Management](PASSWORD-MANAGEMENT.md) - all password options
- [1Password Setup](1PASSWORD-SETUP.md) - the other supported password manager
- [Bitwarden CLI documentation](https://bitwarden.com/help/cli/)
Loading