diff --git a/Cargo.toml b/Cargo.toml index fdc0fa9..329b616 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "signer" -version = "0.0.13" +version = "0.0.14" edition = "2021" license = "MIT" description = "Attended Nostr signing daemon — Rust port of n_signer" diff --git a/deploy_local.sh b/deploy_local.sh new file mode 100755 index 0000000..674a971 --- /dev/null +++ b/deploy_local.sh @@ -0,0 +1,124 @@ +#!/bin/bash +set -e + +# signer (Rust) — Local Deploy Script +# +# Builds release binaries and installs them to /usr/local/bin/. +# +# USAGE: +# ./deploy_local.sh # build release + install +# ./deploy_local.sh --debug # build debug + install +# ./deploy_local.sh -h, --help +# +# Installs: +# /usr/local/bin/signer (the signing daemon) +# /usr/local/bin/signer-client (the CLI client) + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +print_status() { echo -e "${BLUE}[INFO]${NC} $1" >&2; } +print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" >&2; } +print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" >&2; } +print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; } + +PROFILE="release" +CARGO_FLAG="--release" +TARGET_DIR="target/release" + +show_usage() { + echo "signer (Rust) Local Deploy Script" + echo "" + echo "USAGE:" + echo " $0 [OPTIONS]" + echo "" + echo "OPTIONS:" + echo " --debug Build debug profile instead of release" + echo " -h, --help Show this help message" + echo "" + echo "Installs to /usr/local/bin/:" + echo " signer (the signing daemon)" + echo " signer-client (the CLI client)" +} + +while [[ $# -gt 0 ]]; do + case $1 in + --debug) + PROFILE="debug" + CARGO_FLAG="" + TARGET_DIR="target/debug" + shift + ;; + -h|--help) + show_usage + exit 0 + ;; + *) + print_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac +done + +# Check we're in the project root (Cargo.toml present) +if [[ ! -f "Cargo.toml" ]]; then + print_error "Cargo.toml not found. Run this script from the project root." + exit 1 +fi + +# Check the binaries we expect are declared +if ! grep -q 'name = "signer"' Cargo.toml || ! grep -q 'name = "signer-client"' Cargo.toml; then + print_error "Expected binaries 'signer' and 'signer-client' not found in Cargo.toml" + exit 1 +fi + +# Build +print_status "Building ${PROFILE} binaries (cargo build ${CARGO_FLAG})..." +cargo build ${CARGO_FLAG} 2>&1 | tail -5 || { + print_error "Build failed" + exit 1 +} + +SIGNER_BIN="${TARGET_DIR}/signer" +CLIENT_BIN="${TARGET_DIR}/signer-client" + +for bin in "$SIGNER_BIN" "$CLIENT_BIN"; do + if [[ ! -f "$bin" ]]; then + print_error "Built binary not found: $bin" + exit 1 + fi +done + +print_success "Binaries built: $SIGNER_BIN, $CLIENT_BIN" + +# Install to /usr/local/bin +DEST_DIR="/usr/local/bin" + +if [[ ! -d "$DEST_DIR" ]]; then + print_status "Creating $DEST_DIR..." + sudo mkdir -p "$DEST_DIR" +fi + +install_binary() { + local src="$1" + local name + name=$(basename "$src") + print_status "Installing $name to $DEST_DIR/..." + sudo install -m 0755 "$src" "$DEST_DIR/$name" + print_success "Installed: $DEST_DIR/$name" +} + +install_binary "$SIGNER_BIN" +install_binary "$CLIENT_BIN" + +# Verify +print_status "Verification:" +"$DEST_DIR/signer" --version || true +"$DEST_DIR/signer-client" --version || true + +print_success "Local deploy completed (${PROFILE} profile)" diff --git a/src/client/cli.rs b/src/client/cli.rs index 110154b..d9f32a3 100644 --- a/src/client/cli.rs +++ b/src/client/cli.rs @@ -7,7 +7,56 @@ use clap::{Parser, Subcommand}; #[command( name = "signer-client", version = ::signer::VERSION, - about = "Standalone CLI for the signer JSON-RPC API" + about = "Standalone CLI for the signer JSON-RPC API", + after_help = "EXAMPLES: + # List running signer sockets + signer-client list + + # Get signer metadata (auto-discovers the single running socket) + signer-client get-info + + # Get a Nostr public key by role + path + signer-client --role main --path \"m/44'/1237'/0'/0/0\" get-public-key + + # Get a public key by algorithm + index + signer-client --algorithm ed25519 --index 0 get-public-key + + # Sign a raw message (hex) with ed25519 + signer-client --algorithm ed25519 --index 0 sign 68656c6c6f + + # Verify a signature (exit 0 = valid, 1 = invalid) + signer-client --algorithm ed25519 --index 0 verify + + # Sign a Nostr event from stdin and pipe to nak for publishing + echo '{\"kind\":1,\"content\":\"hello nostr\",\"tags\":[],\"created_at\":1700000000}' \\ + | signer-client --role main --path \"m/44'/1237'/0'/0/0\" sign-event \\ + | nak publish + + # NIP-44 encrypt a message to a peer + signer-client --role main --path \"m/44'/1237'/0'/0/0\" nip44-encrypt 'secret' + + # NIP-44 decrypt + signer-client --role main --path \"m/44'/1237'/0'/0/0\" nip44-decrypt + + # Derive an HMAC digest (secp256k1) + signer-client --algorithm secp256k1 --index 0 derive testdata + + # Raw JSON-RPC passthrough + echo '[]' | signer-client call get_info + + # Explicit socket name + signer-client -n signer01 get-info + + # TCP transport (requires auth envelope privkey) + signer-client --tcp host:port --auth-privkey <64-hex> get-info + + # Serial transport (USB CDC-ACM) + signer-client --serial /dev/ttyACM0 get-info + + # Qubes qrexec transport + signer-client --qrexec sys-signer:qubes.SignerRpc get-info + +Run 'signer-client --help' for verb-specific details." )] pub struct Cli { /// Abstract socket name (without @ prefix). Default: auto-discover. diff --git a/src/lib.rs b/src/lib.rs index f8b05cc..21c6389 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,4 +31,4 @@ pub mod error; pub use error::SignerError; /// Version string (matches C NSIGNER_VERSION). -pub const VERSION: &str = "v0.0.13"; +pub const VERSION: &str = "v0.0.14";