sshcommands

package module
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: MIT Imports: 17 Imported by: 0

README

ssh-commands

Go library for SSH/SFTP operations with a parameter-based API: upload (sync), list, delete, download, and fetch server host keys. No config struct dependency; all options are passed as parameters. Optional AES-256-CTR encryption for upload/download.

Go Reference Go Report Card CI

🇩🇪 Deutsche Version

Donationware for CFI Kinderhilfe. License: MIT with attribution (see LICENSE).

Requirements

  • Go 1.25 or later (see go.mod)

Installation

go get github.com/janmz/ssh-commands

Import:

import sshcommands "github.com/janmz/ssh-commands"

Quick Start

opts := &sshcommands.Opts{
    Host:    "example.com",
    Port:    22,
    User:    "deploy",
    KeyFile: "/home/user/.ssh/id_ed25519",
    HostKey: "ed25519 AAAAC3...", // or path to known_hosts
}

localFiles := []sshcommands.LocalFile{
    {Name: "file.zip", Path: "/local/file.zip", ModTime: time.Now(), Size: 1024},
}
err := sshcommands.Sync(opts, localFiles, "/remote/dir", "", nil)

Use at least KeyFile or Password for authentication. HostKey is required for verified connections (file path or inline key line; multiple keys separated by ||).

API Overview

Function Description
Sync Upload missing/newer files; delete remote files not in local list
List List non-directory entries in a remote directory
Delete Remove given file names from a remote directory
Download Download files matching a pattern (*, ? wildcards)
ValidDownloadPattern Validate a download pattern before use
FetchServerHostKey Fetch server host key without verification (setup)
HostKeyAlreadyPresent Check whether a key line is already configured
DialKnownHosts Connect using an OpenSSH known_hosts file
DialWithHostKeyCallback Connect with a custom host key callback
NewSFTPClient Open SSH + SFTP clients (lower-level access)
MkdirAllRemote Create remote directories recursively
UploadFileIfNewer Upload a single file when local is newer
FormatKnownHostsHostToken Build host token for known_hosts entries
AppendKnownHostsLine Append a host token and key line to a file
AppendServerHostKey Fetch and append server key when missing

All operations accept an optional Logger (Info, Warn). Pass nil to disable logging.

Usage

Connection options

Build Opts with SSH connection parameters:

opts := &sshcommands.Opts{
    Host:     "example.com",
    Port:     22,
    User:     "deploy",
    KeyFile:  "/home/user/.ssh/id_ed25519",  // or Password: "<your-password>"
    HostKey:  "ed25519 AAAAC3...",            // or path to known_hosts file
}
Sync (upload and prune)

Upload local files that are missing or newer on the remote; remove remote files that are not in the local list. Optional AES password for encryption.

localFiles := []sshcommands.LocalFile{
    {Name: "file.zip", Path: "/local/file.zip", ModTime: t, Size: 1024},
}
err := sshcommands.Sync(opts, localFiles, "/remote/dir", "", log)
List
entries, err := sshcommands.List(opts, "/remote/dir", log)
// entries: []RemoteEntry{Name, ModTime, Size}
Delete
err := sshcommands.Delete(opts, "/remote/dir", []string{"old.zip"}, log)
Download
if !sshcommands.ValidDownloadPattern("backup_*.zip") {
    // handle invalid pattern
}
paths, err := sshcommands.Download(opts, "backup_*.zip", "/local/dir",
    "/remote/dir", aesPassword, log)
// paths: []string of written local paths
Fetch server host key

Connect without host key verification and return the server’s key line (e.g. for initial setup):

keyLine, err := sshcommands.FetchServerHostKey(opts)
// keyLine: "ed25519 AAAAC3..."
Host key already present
ok, err := sshcommands.HostKeyAlreadyPresent(currentHostKeyValue, newKeyLine)
Connect via known_hosts file
client, err := sshcommands.DialKnownHosts(opts, sshcommands.KnownHostsOptions{
    Path:            "/home/user/.ssh/known_hosts",
    FetchHostKey:    true,  // fetch server key and append when missing
    TrustOnMismatch: true,  // on mismatch, append current key and retry once
}, log)
defer client.Close()

FetchHostKey creates the file when needed. Without it, DialKnownHosts returns an error when the file does not exist.

Upload a single file
client, err := sshcommands.DialKnownHosts(opts, kh, log)
// ...
err = sshcommands.MkdirAllRemote(client, "/remote/dir", log)
err = sshcommands.UploadFileIfNewer(client, "/local/file.zip",
    "/remote/dir/file.zip", log)
Lower-level SFTP access
sftpClient, sshClient, err := sshcommands.NewSFTPClient(opts, log)
defer sshClient.Close()
defer sftpClient.Close()

Encryption

When aesPassword is non-empty, Sync encrypts and Download decrypts using AES-256-CTR with PBKDF2-derived keys (salt + nonce prefix). Format is compatible with streams written by this package.

Development

go vet ./...
go test ./... -v

See CONTRIBUTING.md for pull request guidelines.

Security

Do not commit SSH keys, passwords, or real host names. See SECURITY.md for reporting vulnerabilities and design notes.

License

MIT License — Copyright (c) Jan Neuhaus / VAYA Consulting. See LICENSE.

Documentation

Overview

Package sshcommands provides SSH/SFTP operations (upload, list, delete, download, fetch host key) with parameter-based API, no config dependency.

Index

Constants

View Source
const EncryptionOverhead = saltLen + nonceLen

EncryptionOverhead is the number of bytes added to an encrypted stream (salt + nonce).

Variables

View Source
var (
	// Version is the semantic-like version string of the library.
	// Format: Major.Minor.Patch.Build.
	Version = "0.2.4.2"

	// BuildTime is the timestamp of the build, typically injected via -ldflags
	// at build time.
	BuildTime = "2026-06-24 00:44:59"
)

Functions

func AppendKnownHostsLine

func AppendKnownHostsLine(knownHostsPath, hostToken, keyLine string, log Logger) error

AppendKnownHostsLine appends a host token and key line to a known_hosts file. Parent directories are created as needed.

func AppendServerHostKey

func AppendServerHostKey(opts *Opts, knownHostsPath string, log Logger) (written bool, err error)

AppendServerHostKey fetches the server host key and appends it to knownHostsPath when it is not already present. Returns written=true when a new line was added.

func Delete

func Delete(opts *Opts, remoteDir string, names []string, log Logger) error

Delete removes the given file names from remoteDir.

func DialKnownHosts

func DialKnownHosts(opts *Opts, kh KnownHostsOptions, log Logger) (*ssh.Client, error)

DialKnownHosts connects using KnownHostsOptions.Path for host key verification. opts.HostKey is ignored. When FetchHostKey is set, the server key is fetched and appended when the file is missing or does not contain that key yet.

func DialWithHostKeyCallback

func DialWithHostKeyCallback(opts *Opts, hostKeyCallback ssh.HostKeyCallback, log Logger) (*ssh.Client, error)

DialWithHostKeyCallback connects using a custom host key callback instead of opts.HostKey. opts.HostKey is ignored.

func Download

func Download(opts *Opts, pattern, destDir, remoteDir, aesPassword string, log Logger) ([]string, error)

Download downloads files matching pattern from remoteDir into destDir. Pattern may be a literal filename or contain wildcards (*, ?). No path components. aesPassword empty = no decryption. Returns the list of local paths written.

func FetchServerHostKey

func FetchServerHostKey(opts *Opts) (keyLine string, err error)

FetchServerHostKey connects to the SSH server without host key verification, captures the server's host key, and returns it as a single line (key-type base64…). The client is closed immediately. Use for initial setup (e.g. -setup-ssh).

func FormatKnownHostsHostToken

func FormatKnownHostsHostToken(host string, port int) string

FormatKnownHostsHostToken returns the host token for a known_hosts entry.

func HostKeyAlreadyPresent

func HostKeyAlreadyPresent(currentValue, newKeyLine string) (bool, error)

HostKeyAlreadyPresent returns true if newKeyLine is already among the keys in currentValue (inline " || "-separated keys or path to a file with one key per line).

func MkdirAllRemote

func MkdirAllRemote(client *ssh.Client, remotePath string, log Logger) error

MkdirAllRemote creates remotePath and any missing parent directories via SFTP.

func NewSFTPClient

func NewSFTPClient(opts *Opts, log Logger) (*sftp.Client, *ssh.Client, error)

NewSFTPClient returns an SFTP client; caller must call Close().

func Sync

func Sync(opts *Opts, localFiles []LocalFile, remoteDir, aesPassword string, log Logger) error

Sync uploads local files that are missing or newer on the remote, and deletes remote files that are not in localFiles. remoteDir is created if needed. aesPassword empty = no encryption.

func UploadFileIfNewer

func UploadFileIfNewer(client *ssh.Client, localPath, remotePath string, log Logger) error

UploadFileIfNewer uploads localPath to remotePath when the local file is newer than the remote file or the remote file is missing. Remote parent directories are created as needed and the remote mtime is set to the local mtime.

func ValidDownloadPattern

func ValidDownloadPattern(pattern string) bool

ValidDownloadPattern returns false if pattern contains path components (no /, \, ..).

Types

type KnownHostsOptions

type KnownHostsOptions struct {
	// Path to the known_hosts file (required).
	Path string
	// FetchHostKey connects to the server, captures its host key, and appends
	// it to Path when the file is missing or does not yet contain that key.
	FetchHostKey bool
	// TrustOnMismatch on host key mismatch fetches the current server key,
	// appends it to Path, and retries the connection once.
	TrustOnMismatch bool
}

KnownHostsOptions controls SSH connections that verify the server via an OpenSSH known_hosts file. opts.HostKey is ignored; Path is used instead.

type LocalFile

type LocalFile struct {
	Name    string
	Path    string
	ModTime time.Time
	Size    int64
}

LocalFile describes a local file for Sync (name, path, modtime, size).

type Logger

type Logger interface {
	Info(string, ...interface{})
	Warn(string, ...interface{})
}

Logger is optional for progress and host key mismatch messages; nil = no logging.

type Opts

type Opts struct {
	Host     string // SSH host
	Port     int    // 0 => 22
	User     string
	KeyFile  string // path to private key (optional)
	Password string // plaintext password (optional); at least KeyFile or Password required
	HostKey  string // path to known_hosts file or inline key(s), separated by " || "
}

Opts holds SSH/SFTP connection parameters.

type RemoteEntry

type RemoteEntry struct {
	Name    string
	ModTime time.Time
	Size    int64
}

RemoteEntry describes a remote file (name, modtime, size).

func List

func List(opts *Opts, remoteDir string, log Logger) ([]RemoteEntry, error)

List returns all non-directory entries in remoteDir (name, modtime, size).

Jump to

Keyboard shortcuts

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