crosskey

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 19, 2026 License: MIT Imports: 9 Imported by: 0

README

crosskey

A production-ready Go package that provides unified credential management across Windows, Linux, and WSL (Windows Subsystem for Linux).

One API. Three platforms. Zero configuration.

Features

  • Unified APIGet, Set, and Delete work identically on every platform.
  • Automatic backend detection — the correct credential store is chosen at runtime with no manual configuration.
  • WSL-aware — transparently bridges to the Windows Credential Manager when running inside WSL.
  • Native-first fallback — on WSL, the native Linux keyring (D-Bus Secret Service) is always attempted before falling back to the Windows host.
  • Cached detection — the WSL check reads /proc/sys/kernel/osrelease once and caches the result via sync.Once.

Backends

Environment Backend Mechanism
Windows Native Windows Credential Manager via go-keyring
Linux (non-WSL) Native D-Bus Secret Service (GNOME Keyring / KDE Wallet) via go-keyring
WSL WSL Bridge Tries native Linux keyring first; falls back to powershell.exe (Get) and cmdkey.exe (Set/Delete) on the Windows host

Installation

go get github.com/Gankarloo/crosskey

Quick Start

package main

import (
    "fmt"
    "log"

    "github.com/Gankarloo/crosskey"
)

func main() {
    // Check which backend is active
    fmt.Printf("Backend: %s (WSL: %v)\n", crosskey.ActiveBackend(), crosskey.IsWSL())

    // Store a credential
    if err := crosskey.Set("my-app", "johndoe", "s3cret"); err != nil {
        log.Fatal(err)
    }

    // Retrieve it
    password, err := crosskey.Get("my-app", "johndoe")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Password:", password)

    // Delete it
    if err := crosskey.Delete("my-app", "johndoe"); err != nil {
        log.Fatal(err)
    }
}

API Reference

Functions
Get(service, user string) (string, error)

Retrieves the password for the given service/user pair. Returns ErrNotFound if the credential does not exist.

Set(service, user, password string) error

Stores a credential. All three parameters are required and must be non-empty.

Delete(service, user string) error

Removes a credential. Returns ErrNotFound if the credential does not exist.

IsWSL() bool

Reports whether the process is running inside WSL. The result is cached after the first call.

ActiveBackend() Backend

Returns the backend that will be used for credential operations (BackendNative or BackendWSL).

Sentinel Errors
Variable Description
ErrNotFound Returned when a requested credential does not exist
Types
type Backend int

const (
    BackendNative Backend = iota  // OS-native keyring
    BackendWSL                    // WSL-to-Windows bridge
)

CLI Tool

A small CLI is included for live testing:

# Build
go build -o crosskey-cli ./cmd/crosskey-cli/

# Usage
./crosskey-cli info                              # show detected environment
./crosskey-cli set    <service> <user> <password> # store a credential
./crosskey-cli get    <service> <user>            # retrieve a credential
./crosskey-cli delete <service> <user>            # remove a credential

Project Structure

crosskey/
├── cmd/
│   └── crosskey-cli/
│       └── main.go            # CLI utility for live testing
├── crosskey.go                # Public API, Backend type, WSL detection
├── crosskey_test.go           # Unit tests
├── doc.go                     # Package documentation
├── keyring_native.go          # Native backend (go-keyring wrapper)
├── keyring_wsl.go             # WSL backend (powershell.exe / cmdkey.exe bridge)
├── go.mod
└── go.sum

How WSL Detection Works

  1. Check runtime.GOOS == "linux".
  2. Read /proc/sys/kernel/osrelease.
  3. If the kernel version string contains "microsoft" (case-insensitive), the environment is WSL.
  4. The result is cached with sync.Once/proc is read at most once per process.

How WSL Fallback Works

Each operation follows the same pattern on WSL:

  1. Try native Linux keyring (D-Bus Secret Service) — works when a desktop session or gnome-keyring-daemon is available.
  2. If native fails, bridge to Windows:
    • Getpowershell.exe with Get-StoredCredential or raw Win32 CredRead P/Invoke.
    • Setcmdkey.exe /generic:<service>:<user> /user:<user> /pass:<password>.
    • Deletecmdkey.exe /delete:<service>:<user>.

Security Considerations

WSL Bridge

When the WSL bridge is active, Set passes the password as a command-line argument to cmdkey.exe. This means:

  • ⚠️ The password is briefly visible in /proc/*/cmdline to other processes on the same WSL instance.
  • ⚠️ Other users with access to the WSL instance could potentially observe it.

Mitigations:

  • The native Linux keyring is always attempted first — the bridge is only used when D-Bus is unavailable.
  • For high-security environments, ensure a D-Bus session is active so the native backend succeeds, or use an alternative vault.
General
  • Input validation rejects empty service, user, or password values at the API boundary.
  • ErrNotFound is normalized across backends to provide a consistent sentinel for "not found" checks.

Requirements

  • Go 1.26+
  • Linux (non-WSL): A running D-Bus session with a Secret Service provider (e.g., gnome-keyring-daemon).
  • WSL: Either a D-Bus session or access to powershell.exe / cmdkey.exe on the Windows host.
  • Windows: No additional dependencies.

Environment Variables

  • CROSSKEY_FORCE_WINDOWS — When running inside WSL, forces the Windows bridge even if the native Linux keyring is available. Only the values 1 or true (case-insensitive, leading/trailing whitespace ignored) are treated as enabled. Any other value or an empty string disables the override. This setting is ignored on non-WSL Linux and Windows.

License

See repository root for license information.

Documentation

Overview

Package crosskey provides a unified credential management API that works transparently across Windows, standard Linux, and WSL (Windows Subsystem for Linux).

Backends

The package automatically selects the correct backend at runtime:

  • Windows (runtime.GOOS == "windows"): delegates to the native Windows Credential Manager via github.com/zalando/go-keyring.

  • Linux (non-WSL): delegates to the D-Bus Secret Service (GNOME Keyring, KDE Wallet, etc.) via github.com/zalando/go-keyring.

  • WSL: first attempts the native Linux keyring; if that fails (common when no D-Bus session is available), falls back to bridging into the Windows host by invoking powershell.exe and cmdkey.exe.

Usage

import "github.com/Gankarloo/crosskey"

// Store a credential err := crosskey.Set("my-app", "johndoe", "s3cret")

// Retrieve a credential password, err := crosskey.Get("my-app", "johndoe")

// Delete a credential err = crosskey.Delete("my-app", "johndoe")

Security Considerations

On WSL the package must invoke Windows executables (cmdkey.exe, powershell.exe) with credential material passed as command-line arguments. This means:

  • The password is briefly visible in the process list (/proc/*/cmdline).
  • Other users on the same WSL instance could potentially observe it.

For environments where this is unacceptable, consider storing secrets exclusively in the native Linux keyring or using an alternative vault.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = fmt.Errorf("crosskey: secret not found")

ErrNotFound is returned when a requested credential does not exist.

Functions

func Delete

func Delete(service, user string) error

Delete removes the credential for the given service and user.

On WSL it first attempts the native Linux keyring; if that fails it transparently falls back to the Windows Credential Manager.

func Get

func Get(service, user string) (string, error)

Get retrieves the password for the given service and user.

On WSL it first attempts the native Linux keyring; if that fails it transparently falls back to the Windows Credential Manager.

func IsWSL

func IsWSL() bool

IsWSL reports whether the current process is running inside Windows Subsystem for Linux. The result is cached after the first call.

func Set

func Set(service, user, password string) error

Set stores a credential for the given service and user.

On WSL it first attempts the native Linux keyring; if that fails it transparently falls back to the Windows Credential Manager.

SECURITY NOTE (WSL): the password is passed as a command-line argument to cmdkey.exe and is therefore briefly visible in the process list.

Types

type Backend

type Backend int

Backend identifies the credential storage backend in use.

const (
	// BackendNative represents the OS-native keyring (Windows Credential
	// Manager on Windows, D-Bus Secret Service on Linux).
	BackendNative Backend = iota
	// BackendWSL represents the WSL-to-Windows bridge that calls
	// powershell.exe / cmdkey.exe on the Windows host.
	BackendWSL
)

func ActiveBackend

func ActiveBackend() Backend

ActiveBackend returns the backend that will be used for credential operations in the current environment.

func (Backend) String

func (b Backend) String() string

String returns a human-readable name for the backend.

Directories

Path Synopsis
cmd
crosskey-cli command
crosskey-cli is a small utility for live-testing the crosskey package.
crosskey-cli is a small utility for live-testing the crosskey package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL