wgctl/modules/identity.module.sh
Nuno Duque Nunes 8bb1de4976 init feature
2026-05-19 15:26:31 +00:00

212 lines
No EOL
7.2 KiB
Bash

#!/usr/bin/env bash
# identity.module.sh — identity file management and peer-name inference
# ===========================================================================
# Path helpers
# ===========================================================================
function identity::path() {
local name="${1:-}"
echo "$(ctx::identities)/${name}.identity"
}
# ===========================================================================
# Existence checks
# ===========================================================================
function identity::exists() {
local name="${1:-}"
json::identity_exists "$(identity::path "$name")" 2>/dev/null
}
function identity::require_exists() {
local name="${1:-}"
if ! identity::exists "$name"; then
log::error "Identity '${name}' not found. Use 'wgctl identity list' to see all identities."
return 1
fi
}
function identity::require_not_exists() {
local name="${1:-}"
if identity::exists "$name"; then
log::error "Identity '${name}' already exists."
return 1
fi
}
# ===========================================================================
# Peer name inference
# ===========================================================================
# identity::infer <peer_name>
# Parses a peer name and returns "identity_name|type|index" if it matches
# the naming convention, or empty string if not.
# phone-nuno -> "nuno|phone|1"
# phone-nuno-2 -> "nuno|phone|2"
# roboclean -> "" (no type prefix)
function identity::infer() {
local peer_name="${1:-}"
json::identity_infer "$peer_name" 2>/dev/null || true
}
# identity::next_index <identity_name> <type>
# Returns the next available device index for a type within an identity.
# If identity doesn't exist yet, returns 1.
function identity::next_index() {
local identity_name="${1:-}" peer_type="${2:-}"
local id_file
id_file=$(identity::path "$identity_name")
if [[ ! -f "$id_file" ]]; then
echo 1
return 0
fi
json::identity_next_index "$id_file" "$peer_type" 2>/dev/null || echo 1
}
# ===========================================================================
# Auto-attach (called from wgctl add)
# ===========================================================================
# identity::auto_attach <peer_name> <peer_type>
# Infers identity from peer name and adds the peer to the identity file.
# Creates the identity file if it doesn't exist.
# Silent — no output. Logs a note on success, silently skips if no match.
function identity::auto_attach() {
local peer_name="${1:-}" peer_type="${2:-}"
local inferred
inferred=$(identity::infer "$peer_name")
[[ -z "$inferred" ]] && return 0
local identity_name type_inferred index
identity_name=$(echo "$inferred" | cut -d'|' -f1)
type_inferred=$(echo "$inferred" | cut -d'|' -f2)
index=$(echo "$inferred" | cut -d'|' -f3)
# Use the explicit type if provided, otherwise use inferred type
local final_type="${peer_type:-$type_inferred}"
local id_file
id_file=$(identity::path "$identity_name")
json::identity_add_peer "$id_file" "$identity_name" "$peer_name" "$final_type" "$index" </dev/null
log::info "Attached '${peer_name}' to identity '${identity_name}' (${final_type} #${index})"
}
# identity::auto_detach <peer_name>
# Removes a peer from its identity file when the peer is deleted.
# If the identity has no remaining peers, removes the identity file too.
function identity::auto_detach() {
local peer_name="${1:-}"
local inferred
inferred=$(identity::infer "$peer_name")
[[ -z "$inferred" ]] && return 0
local identity_name
identity_name=$(echo "$inferred" | cut -d'|' -f1)
local id_file
id_file=$(identity::path "$identity_name")
[[ ! -f "$id_file" ]] && return 0
json::identity_remove_peer "$id_file" "$peer_name" </dev/null
# Remove identity file if now empty
local remaining
remaining=$(json::identity_peers "$id_file" 2>/dev/null) || true
if [[ -z "$remaining" ]]; then
rm -f "$id_file"
log::info "Identity '${identity_name}' removed (no remaining peers)"
fi
}
# ===========================================================================
# Peer queries
# ===========================================================================
# identity::peers <identity_name> [type_filter]
# Returns peer names belonging to an identity, one per line.
# Optional type_filter limits to peers of a specific type.
function identity::peers() {
local identity_name="${1:-}" type_filter="${2:-}"
local id_file
id_file=$(identity::path "$identity_name")
json::identity_peers "$id_file" "$type_filter" 2>/dev/null || true
}
# identity::get_name <peer_name>
# Returns the identity name for a given peer (via inference).
function identity::get_name() {
local peer_name="${1:-}"
local inferred
inferred=$(identity::infer "$peer_name")
[[ -n "$inferred" ]] && echo "${inferred%%|*}"
}
# ===========================================================================
# Data for commands
# ===========================================================================
function identity::list_data() {
json::identity_list "$(ctx::identities)" 2>/dev/null || true
}
function identity::show_data() {
local name="${1:-}"
json::identity_show "$(identity::path "$name")" 2>/dev/null
}
# ===========================================================================
# Rename helper (called from rename.command.sh)
# ===========================================================================
# identity::rename_peer <old_peer_name> <new_peer_name>
# Updates identity file entry when a peer is renamed.
# Re-infers identity from old name, removes old entry, adds new entry.
function identity::rename_peer() {
local old_name="${1:-}" new_name="${2:-}"
local old_inferred
old_inferred=$(identity::infer "$old_name")
[[ -z "$old_inferred" ]] && return 0
local identity_name old_type old_index
identity_name=$(echo "$old_inferred" | cut -d'|' -f1)
old_type=$(echo "$old_inferred" | cut -d'|' -f2)
old_index=$(echo "$old_inferred" | cut -d'|' -f3)
local id_file
id_file=$(identity::path "$identity_name")
[[ ! -f "$id_file" ]] && return 0
# Infer new identity context from new name
local new_inferred new_identity new_type new_index
new_inferred=$(identity::infer "$new_name")
if [[ -n "$new_inferred" ]]; then
new_identity=$(echo "$new_inferred" | cut -d'|' -f1)
new_type=$(echo "$new_inferred" | cut -d'|' -f2)
new_index=$(echo "$new_inferred" | cut -d'|' -f3)
else
# New name doesn't match convention — detach cleanly
json::identity_remove_peer "$id_file" "$old_name" </dev/null
return 0
fi
# Remove old entry
json::identity_remove_peer "$id_file" "$old_name" </dev/null
if [[ "$new_identity" == "$identity_name" ]]; then
# Same identity — update in place
json::identity_add_peer "$id_file" "$identity_name" "$new_name" "$new_type" "$new_index" </dev/null
else
# Identity changed (e.g. phone-nuno -> phone-helena) — move to new identity file
local new_id_file
new_id_file=$(identity::path "$new_identity")
json::identity_add_peer "$new_id_file" "$new_identity" "$new_name" "$new_type" "$new_index" </dev/null
# Clean up old identity if empty
local remaining
remaining=$(json::identity_peers "$id_file" 2>/dev/null) || true
if [[ -z "$remaining" ]]; then
rm -f "$id_file"
fi
fi
}