diff --git a/bin/disinto b/bin/disinto index a4dc192..b0893c4 100755 --- a/bin/disinto +++ b/bin/disinto @@ -2885,12 +2885,23 @@ disinto_edge() { edge_host="${EDGE_HOST:-edge.disinto.ai}" fi + # Read tunnel pubkey for ownership proof + local secrets_dir="${FACTORY_ROOT}/secrets" + local tunnel_pubkey="${secrets_dir}/tunnel_key.pub" + if [ ! -f "$tunnel_pubkey" ]; then + echo "Error: tunnel keypair not found at ${tunnel_pubkey}" >&2 + echo "Cannot prove ownership without the tunnel public key." >&2 + exit 1 + fi + local pubkey + pubkey=$(tr -d '\n' < "$tunnel_pubkey") + # SSH to edge host and deregister echo "Deregistering tunnel for ${project} on ${edge_host}..." local response response=$(ssh -o StrictHostKeyChecking=accept-new -o BatchMode=yes \ "disinto-register@${edge_host}" \ - "deregister ${project}" 2>&1) || { + "deregister ${project} ${pubkey}" 2>&1) || { echo "Error: failed to deregister tunnel" >&2 echo "Response: ${response}" >&2 exit 1 diff --git a/tools/edge-control/register.sh b/tools/edge-control/register.sh index 298ae0b..850a172 100755 --- a/tools/edge-control/register.sh +++ b/tools/edge-control/register.sh @@ -11,7 +11,7 @@ # # Usage (via SSH): # ssh disinto-register@edge "register " -# ssh disinto-register@edge "deregister " +# ssh disinto-register@edge "deregister " # ssh disinto-register@edge "list" # # Output: JSON on stdout @@ -90,7 +90,7 @@ usage() { cat < Register a new tunnel - deregister Remove a tunnel + deregister Remove a tunnel (requires owner pubkey) list List all registered tunnels Example: @@ -231,9 +231,15 @@ do_register() { } # Deregister a tunnel -# Usage: do_deregister +# Usage: do_deregister do_deregister() { local project="$1" + local caller_pubkey="$2" + + if [ -z "$caller_pubkey" ]; then + echo '{"error":"deregister requires "}' + exit 1 + fi # Record who is deregistering before removal local deregistered_by="$CALLER" @@ -247,13 +253,16 @@ do_deregister() { exit 1 fi - pubkey_fp=$(get_project_info "$project" | jq -r '.pubkey // empty' 2>/dev/null) || pubkey_fp="" - if [ -n "$pubkey_fp" ]; then - pubkey_fp=$(ssh-keygen -lf /dev/stdin <<<"$pubkey_fp" 2>/dev/null | awk '{print $2}') || pubkey_fp="unknown" - else - pubkey_fp="unknown" + # Verify caller owns this project — pubkey must match stored value + local stored_pubkey + stored_pubkey=$(get_project_info "$project" | jq -r '.pubkey // empty' 2>/dev/null) || stored_pubkey="" + if [ "$caller_pubkey" != "$stored_pubkey" ]; then + echo '{"error":"pubkey mismatch"}' + exit 1 fi + pubkey_fp=$(ssh-keygen -lf /dev/stdin <<<"$stored_pubkey" 2>/dev/null | awk '{print $2}') || pubkey_fp="unknown" + # Remove from registry free_port "$project" >/dev/null @@ -335,13 +344,17 @@ main() { do_register "$project" "$pubkey" ;; deregister) - # deregister - local project="$args" - if [ -z "$project" ]; then - echo '{"error":"deregister requires "}' + # deregister + local project="${args%% *}" + local pubkey="${args#* }" + if [ "$pubkey" = "$args" ]; then + pubkey="" + fi + if [ -z "$project" ] || [ -z "$pubkey" ]; then + echo '{"error":"deregister requires "}' exit 1 fi - do_deregister "$project" + do_deregister "$project" "$pubkey" ;; list) do_list