621e8895c9
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
package infra
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
// WGKeys holds a WireGuard Curve25519 key pair and an optional preshared key,
|
|
// all encoded as base64 strings.
|
|
type WGKeys struct {
|
|
PrivateKey string // base64 Curve25519 private key
|
|
PublicKey string // base64 Curve25519 public key
|
|
PresharedKey string // base64 preshared key, empty if not requested
|
|
}
|
|
|
|
// WGKeygen generates a WireGuard key pair using `wg genkey` / `wg pubkey`.
|
|
// If withPSK is true it also runs `wg genpsk` to produce a preshared key.
|
|
// Requires the `wg` binary in PATH (install wireguard-tools).
|
|
// NEVER log PrivateKey or PresharedKey in plain text.
|
|
func WGKeygen(withPSK bool) (WGKeys, error) {
|
|
// Generate private key
|
|
privOut, err := runWG(nil, "genkey")
|
|
if err != nil {
|
|
return WGKeys{}, fmt.Errorf("wg genkey: %w", err)
|
|
}
|
|
privateKey := strings.TrimSpace(privOut)
|
|
|
|
// Derive public key from private key
|
|
pubOut, err := runWG(strings.NewReader(privateKey), "pubkey")
|
|
if err != nil {
|
|
return WGKeys{}, fmt.Errorf("wg pubkey: %w", err)
|
|
}
|
|
publicKey := strings.TrimSpace(pubOut)
|
|
|
|
keys := WGKeys{
|
|
PrivateKey: privateKey,
|
|
PublicKey: publicKey,
|
|
}
|
|
|
|
if withPSK {
|
|
pskOut, err := runWG(nil, "genpsk")
|
|
if err != nil {
|
|
return WGKeys{}, fmt.Errorf("wg genpsk: %w", err)
|
|
}
|
|
keys.PresharedKey = strings.TrimSpace(pskOut)
|
|
}
|
|
|
|
return keys, nil
|
|
}
|
|
|
|
// runWG executes `wg <subcommand>`, optionally piping stdin, and returns stdout.
|
|
// stderr is captured and included in the error when exit code != 0.
|
|
func runWG(stdin interface{ Read([]byte) (int, error) }, subcommand string) (string, error) {
|
|
cmd := exec.Command("wg", subcommand)
|
|
if stdin != nil {
|
|
cmd.Stdin = stdin
|
|
}
|
|
var stdout, stderr bytes.Buffer
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
if err := cmd.Run(); err != nil {
|
|
return "", fmt.Errorf("%w: %s", err, strings.TrimSpace(stderr.String()))
|
|
}
|
|
return stdout.String(), nil
|
|
}
|