Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
289817e
Refactor Windows credential management to use direct API calls instea…
Apr 1, 2026
c2947a0
Fix password encoding in writeWindowsCredential to handle errors corr…
Apr 1, 2026
213a80b
feat: Also fetch username from 1password
Apr 1, 2026
f50ca16
feat: Add RDP Gateway support with credential management and UI integ…
Apr 3, 2026
4fb7404
feat: Enhance RDP connection options and improve UI
Apr 21, 2026
97d8504
feat: Hide console window for 1Password CLI commands to improve user …
Apr 21, 2026
1e35eac
No longer needed to enter password in case of gateway
Apr 22, 2026
c8d7572
Merge pull request #1 from janvdpol/feat/RDP-gateway-support
janvdpol Apr 22, 2026
dad6e16
feat: Add CLAUDE.md for project guidance and build instructions
May 6, 2026
f63ccf3
feat: Implement double-click connection selection for faster access
May 6, 2026
dd0e009
feat: Enhance 1Password integration with batched secret resolution an…
May 6, 2026
8939b14
feat: Enhance connection tree with double-tap functionality and progr…
May 6, 2026
4579b75
feat: Optimize build commands for Windows and Linux with additional f…
May 6, 2026
c92d6fc
feat: Add Windows icon embedding and resource generation to build pro…
May 6, 2026
7d45baf
feat: Update README and CHANGELOG for double-click connection and Win…
May 6, 2026
f9573b2
fix: Update version in CHANGELOG to 1.1.1 for release
May 6, 2026
8ae0543
feat: Update GitHub Actions and settings for improved functionality a…
May 6, 2026
eefdf10
fix: Update Go version to 1.24 in build workflow
May 6, 2026
50429ba
fix: Simplify error handling for 1Password reference resolution in La…
May 6, 2026
c861ea5
feat: Implement cleanup functionality on startup and application exit…
May 6, 2026
ebd71b8
feat: Enhance RDP connection handling by refining waitForMstscConnect…
May 6, 2026
0799296
feat: Document automatic RDP session cleanup and technical details in…
May 6, 2026
68a3eba
feat: Implement git status checking and notification for config updates
May 27, 2026
858dc45
Refactor code structure for improved readability and maintainability
May 27, 2026
e9dcd01
feat: Add RDP local drive redirection and fix git-status startup crash
Aug 14, 2026
e622acc
feat: Add self-update via GitHub Releases
Aug 14, 2026
a98a9d2
feat: Verify self-update archives against published SHA-256 checksums
Aug 14, 2026
41eaadc
fix: Publish releases as stable by tag naming, not permanently pre-re…
Aug 14, 2026
09a9c32
ci: Exclude build paths from Windows Defender to speed up the Windows…
Aug 14, 2026
49dbb6c
ci: Cache the go-winres tool binary instead of rebuilding it every run
Aug 14, 2026
23132f5
ci: Build on every push to main to keep the release cache warm
Aug 14, 2026
9666179
ci: Bump pinned Actions to latest, fixing the Node 20 deprecation war…
Aug 14, 2026
35ec6b3
feat: Make connection name and host selectable in the details panel
Oct 23, 2026
43dd550
fix: Open RDP on macOS via a temporary .rdp file instead of an rdp://…
Nov 9, 2026
61f2768
feat: Put the RDP password on the clipboard on macOS
Nov 9, 2026
2133251
ci: Build macOS on macos-26 now that macos-14 runners are retired
Nov 9, 2026
a2f1cbb
feat: Use sdl-freerdp for RDP on macOS when installed
Nov 9, 2026
7841484
docs: Document macOS RDP clients and drop the FreeRDP test checklist
Nov 9, 2026
98c3d7b
docs: Add the macOS RDP client documentation and changelog entries
Nov 9, 2026
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
13 changes: 13 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"permissions": {
"allow": [
"Bash(go build:*)",
"Bash(make build *)",
"WebSearch"
],
"additionalDirectories": [
"c:\\github\\jaydenthorup\\mremotego",
"c:\\github\\jaydenthorup\\mremotego\\bin"
]
}
}
15 changes: 15 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"permissions": {
"allow": [
"Bash(xargs grep *)",
"Bash(go vet *)",
"Bash(git *)",
"Bash(go test *)",
"Bash(go env *)",
"Bash(grep -n *)",
"Bash(Get-Content *)",
"WebFetch(domain:github.com)",
"WebFetch(domain:api.github.com)"
]
}
}
108 changes: 96 additions & 12 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@ name: Build Cross-Platform

on:
push:
branches: [ main ] # Also keeps main's build cache warm — see below
tags:
- 'v*.*.*' # Only trigger on version tags like v1.0.0
pull_request:
branches: [ main ]
workflow_dispatch: # Allow manual trigger

# GitHub Actions caches (actions/setup-go's module+build cache here) are only
# restorable from the exact same ref or the repository's default branch — a
# newly-pushed release tag has never been built before, so with no build on
# `main` it always started from a fully cold cache. Confirmed via timing: the
# Windows build (the slowest by far, due to CGO compiling Fyne's OpenGL
# bindings) took ~380-400s cold, but only ~35s once main's cache was warm.
# Building on every push to main keeps that cache hot, so tag-triggered
# release builds inherit it instead of starting cold every time.

jobs:
build:
name: Build ${{ matrix.os }}
Expand All @@ -27,7 +37,11 @@ jobs:
goos: windows
goarch: amd64
name: mremotego-windows-amd64.exe
- os: macos-14
# macos-14 runners were retired on 2026-11-02 ("configuration not
# supported"). Pinned rather than macos-latest so image upgrades are
# deliberate; MACOSX_DEPLOYMENT_TARGET in the build step keeps the
# binary runnable on older macOS versions than the runner's.
- os: macos-26
goos: darwin
goarch: arm64
name: mremotego-darwin-arm64
Expand All @@ -39,43 +53,92 @@ jobs:
# name: mremotego-darwin-amd64

steps:
- name: Exclude build paths from Windows Defender scanning
# CGO builds (needed for Fyne's OpenGL bindings) write large numbers of
# object files during compilation, and Windows Defender's real-time
# scanning of each one is the single biggest reason this job takes far
# longer than the Linux/macOS builds of the same code (~7min vs
# ~40s-2.5min). Safe here since the runner is an ephemeral, single-use VM.
if: matrix.os == 'windows-latest'
shell: powershell
run: |
Add-MpPreference -ExclusionPath "${{ github.workspace }}", "$env:LOCALAPPDATA", "$env:USERPROFILE\go"

- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7.0.1

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7.0.0
with:
go-version: '1.23'
go-version: '1.24'
cache: true

- 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: Cache go-winres binary
# go-winres itself never changes between builds, but "go install ...@latest"
# re-resolves and rebuilds it from source on every single run regardless
# (~40s wasted). Pinning the version and caching the compiled binary
# turns that into a one-time cost.
if: matrix.os == 'windows-latest'
id: cache-go-winres
uses: actions/cache@v6.1.0
with:
path: ~/go/bin/go-winres.exe
key: go-winres-v0.3.3-windows-amd64

- name: Install go-winres (Windows icon embedding)
if: matrix.os == 'windows-latest' && steps.cache-go-winres.outputs.cache-hit != 'true'
run: go install github.com/tc-hib/go-winres@v0.3.3

- name: Generate Windows resources
if: matrix.os == 'windows-latest'
working-directory: cmd/mremotego-gui
run: go-winres simply --icon Icon.png --arch amd64

- name: Determine version
id: version
shell: bash
run: |
# Embedded into the binary for the About dialog and self-update checks
# (see cmd/mremotego-gui/main.go). Only tag pushes get a real version —
# PR/workflow_dispatch builds stay "dev", which disables update checks.
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
echo "value=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
else
echo "value=dev" >> "$GITHUB_OUTPUT"
fi

- name: Build (Windows)
if: matrix.os == 'windows-latest'
env:
CGO_ENABLED: 1
run: |
go build -ldflags "-H windowsgui" -o ${{ matrix.name }} ./cmd/mremotego-gui
go build -ldflags "-s -H windowsgui -X main.version=${{ steps.version.outputs.value }}" -o ${{ matrix.name }} ./cmd/mremotego-gui

- name: Build (Linux)
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm'
env:
CGO_ENABLED: 1
run: |
go build -o ${{ matrix.name }} ./cmd/mremotego-gui
go build -ldflags "-s -X main.version=${{ steps.version.outputs.value }}" -o ${{ matrix.name }} ./cmd/mremotego-gui

- name: Build (macOS)
if: startsWith(matrix.os, 'macos')
env:
CGO_ENABLED: 1
# Without this, clang targets the runner's own macOS version for the
# cgo (Fyne/GLFW) code, and the binary may refuse to start on older Macs.
MACOSX_DEPLOYMENT_TARGET: '12.0'
run: |
go build -o ${{ matrix.name }} ./cmd/mremotego-gui
go build -ldflags "-X main.version=${{ steps.version.outputs.value }}" -o ${{ matrix.name }} ./cmd/mremotego-gui

- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7.0.1
with:
name: ${{ matrix.goos }}-${{ matrix.goarch }}
path: ${{ matrix.name }}
Expand All @@ -89,10 +152,10 @@ jobs:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7.0.1

- name: Download all artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8.0.1
with:
path: artifacts

Expand All @@ -118,19 +181,40 @@ jobs:
done
ls -lh

- name: Generate checksums
# Consumed by internal/update's self-updater to verify a downloaded
# archive before installing it (see verifyChecksum in update.go).
run: |
cd artifacts
sha256sum *.tar.gz *.zip > SHA256SUMS
cat SHA256SUMS

- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT

- name: Determine release type
id: release_type
run: |
# Plain tags (v1.6.0) publish as a real release; tags carrying a
# semver pre-release identifier (v2.0.0-alpha, -beta, -rc1, ...)
# publish as a GitHub pre-release.
if [[ "${{ steps.version.outputs.VERSION }}" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
fi

- name: Create Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3.0.2
with:
name: Release ${{ steps.version.outputs.VERSION }}
draft: false
prerelease: true
prerelease: ${{ steps.release_type.outputs.prerelease }}
generate_release_notes: true
files: |
artifacts/*.tar.gz
artifacts/*.zip
artifacts/SHA256SUMS
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Binaries for programs and plugins
*.exe
*.exe*
*.exe~
*.dll
*.so
Expand Down Expand Up @@ -42,3 +42,7 @@ dist/
connections.yaml
config.yaml
MremoteGO-Config.xml

# Generated Windows icon resources (produced by go-winres during build)
cmd/mremotego-gui/rsrc_windows_*.syso
cmd/mremotego-gui/icon.ico
81 changes: 81 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,87 @@ 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
- **macOS RDP auto-login via FreeRDP**: when FreeRDP's SDL client (`sdl-freerdp`, `brew install freerdp`) is installed, macOS RDP connections use it instead of Windows App. Credentials from 1Password are passed in automatically. All arguments, passwords included, go through `/args-from:stdin`, so they never appear in `ps`. MremoteGO looks for the client in PATH and in the Homebrew/MacPorts directories, so it is also found when started from Finder. Connection settings are mapped to FreeRDP options: gateway, certificate level, NLA, drive redirection, resolution and colour depth. Connections whose RD Gateway uses smartcard authentication keep using Windows App. `MREMOTEGO_MAC_RDP_CLIENT=freerdp|windowsapp` forces a client.

## [1.7.3] - 2026-11-09

### Fixed
- **macOS build**: CI now builds on the `macos-26` runner, because `macos-14` was retired ("The configuration 'macos-14-arm64-us-default' is not supported"). `MACOSX_DEPLOYMENT_TARGET=12.0` keeps the binary runnable on older macOS versions.

## [1.7.2] - 2026-11-09

### Added
- **macOS RDP password via the clipboard**: Windows App and Microsoft Remote Desktop ignore passwords in `.rdp` files, so the password (from 1Password) is put on the clipboard to paste into the client's prompt. It is marked Concealed/Transient so clipboard managers skip it, and it is removed after 45 seconds or when MremoteGO closes. The status bar says when the password is ready.

## [1.7.1] - 2026-11-09

### Fixed
- **macOS RDP "The URL is not valid"**: RDP on macOS opened an `rdp://user@domain@host` URL that Windows App rejects. It now opens a temporary `.rdp` file with the default handler, so port, domain, gateway and drive settings also carry over.

## [1.6.1] - 2026-08-14

### Fixed
- **Releases now publish as stable, not permanently pre-release**: `prerelease` was previously hardcoded to `true` for every release the workflow created, with nothing ever able to graduate it — this is the first release published as a real (non-prerelease) GitHub release. Going forward, a plain tag (`v1.6.1`) publishes as stable; a tag carrying a semver pre-release identifier (`v2.0.0-alpha`, `-beta`, `-rc1`) publishes as a pre-release.
- **Self-update no longer offers pre-releases**: `internal/update.CheckLatest` now skips prerelease entries when picking "latest" (in addition to drafts), so an alpha/beta tag pushed in the future won't get auto-offered to everyone on the stable channel — only a plain, stable tag will. Releases 1.0.0 through 1.6.0 remain marked as pre-release on GitHub itself (a historical label, harmless — self-update simply treats this release as the first stable one to offer).

## [1.6.0] - 2026-08-14

### Added
- **Self-update integrity verification**: the release workflow now publishes a `SHA256SUMS` file alongside each platform archive, and the self-updater (introduced in 1.5.0) verifies a downloaded archive's SHA-256 against it before installing. This fails closed: a release with no `SHA256SUMS` asset, no matching entry for the current platform, or a hash mismatch is treated as a failed update and nothing is installed. Downloads were already served over GitHub's HTTPS, but self-updating bypasses the Mark-of-the-Web/SmartScreen check a manually-downloaded-and-extracted exe would normally get, so this restores an integrity check in its place.

## [1.5.0] - 2026-08-14

### Added
- **Self-update**: MremoteGO now checks GitHub Releases for a newer version — silently a few seconds after startup (only interrupting the user when an update is actually found), and on demand via the new "Check for Updates..." item in the Help menu. When available, a dialog shows the release notes and lets the user confirm before it downloads the matching platform archive, replaces the running executable, and relaunches automatically. Supported on Windows, Linux, and macOS:
- Windows: the running exe is renamed aside (`<exe>.old`) before the new one is moved into place, since Windows allows renaming but not overwriting a running executable; the leftover is cleaned up shortly after the next startup.
- Linux/macOS: the executable's directory entry is replaced directly — safe because the already-running process keeps executing off its existing (now-unlinked) file handle.
- All releases from this project are published as GitHub prereleases, so the update check queries the release list rather than the `/releases/latest` endpoint (which excludes prereleases and always 404s here).
- The running version is now embedded into the binary at build time (`-X main.version=...`, wired through `Makefile`, `build-gui.ps1`, and the CI release workflow) and shown in the About dialog, which previously hardcoded "v1.0".

## [1.4.0] - 2026-08-14

### Added
- **RDP local drive redirection**: RDP connections can now map local drives into the remote session. Configurable via the new "Redirect local drives" option in the Add/Edit Connection dialogs, or the `rdp_redirect_drives` YAML field. Four modes are supported:
- **All drives** (`"*"`) — every local drive present now, plus any connected later
- **All local disks only (no network drives)** (`"local"`) — local fixed/removable drives present at launch time, resolved via `GetDriveTypeW` to exclude network-mapped drive letters
- **Dynamic drives** (`"dynamic"`) — only drives connected after the session starts (e.g. USB sticks), maps to the `.rdp` file's `DynamicDrives` token
- **Specific drives** (e.g. `"C,D"`) — an explicit comma-separated list of drive letters

Windows exposes redirected drives both as new volumes under "This PC" and as subdirectories under `\\tsclient`. Implemented via the `.rdp` file's `drivestoredirect` setting.

### Fixed
- **Startup crash from git status checking**: the background config-git-status check (added in 1.3.0) called Fyne widget and dialog methods directly from a goroutine instead of marshalling them onto the main UI thread via `fyne.Do`, which newer Fyne versions treat as a fatal thread-safety violation. Affected `notifyIfConfigOutdated`, `startPeriodicGitCheck`, and the "pull latest config" confirmation flow in `cmd/mremotego-gui/main.go`.

## [1.3.0] - 2026-05-27

### Added
- **Git status checking for config updates**: on startup (and every 15 minutes thereafter), MremoteGo checks whether the config repository's local `HEAD` is behind its remote via `git ls-remote` (read-only, no fetch). A status indicator appears in the status bar, and if the config is behind, a dialog offers to `git pull` the latest version and reload it automatically.

## [1.2.0] - 2026-05-06

### Added
- **Automatic RDP session cleanup**: credentials and temporary `.rdp` files created by MRemoteGo are now fully cleaned up at the right moment — whichever comes first: immediately after authentication completes (detected by mstsc's window title containing the hostname), when the session closes, when the app is closed, or on next startup after a crash. Every credential is tagged with `Comment = "Managed by MRemoteGo"` so orphaned entries can be identified and removed. Multiple concurrent RDP sessions are tracked and cleaned up independently.

## [1.1.1] - 2026-05-06

### Added
- **Windows taskbar icon**: application icon is now embedded in the `.exe` PE resource section via `go-winres`, so it persists when the app is pinned to the Windows taskbar
- **1Password batched resolution**: credentials from the same vault+item are now fetched in a single `op item get --format json` call instead of one call per field, reducing biometric prompts
- **Unit tests for 1Password**: `ResolveMultiple` is covered by four tests (same-item batching, different items, non-reference passthrough, duplicate deduplication)

### Changed
- **Double-click to connect**: now uses Fyne's `DoubleTappable` interface for reliable detection; single-click still selects and shows connection details
- Double-clicking a connection selects the item, populates the details panel, and shows the knight-rider progress bar — matching the behaviour of the Connect button
- `build-gui.ps1` and GitHub Actions Windows build now run `go-winres` before compilation to regenerate icon resources automatically
- Windows build now compiles from the package path (`./cmd/mremotego-gui/`) so `.syso` resource files are automatically included

### Fixed
- Double-click no longer silently fails when clicking an already-selected tree item (root cause: Fyne fires `Tapped` *or* `DoubleTapped`, never both)
- Single-click selection broke when `DoubleTappable` was added; fixed by implementing both `Tappable` and `DoubleTappable` on the tree node widget and driving `tree.Select` explicitly

## [1.0.4] - 2026-01-28

### Fixed
Expand Down
Loading