Última atividade 1 month ago

Revisão ea2ee3535a82b49d7a3539cf8000f49baddd3891

gistfile1.txt Bruto
1#!/usr/bin/env bash
2# identity.module.sh — identity file management and peer-name inference
3
4# ===========================================================================
5# Path helpers
6# ===========================================================================
7
8function identity::path() {
9 local name="${1:-}"
10 echo "$(ctx::identities)/${name}.identity"
11}
12
13# ===========================================================================
14# Existence checks
15# ===========================================================================
16
17function identity::exists() {
18 local name="${1:-}"
19 json::identity_exists "$(identity::path "$name")" 2>/dev/null
20}
21
22function identity::require_exists() {
23 local name="${1:-}"
24 if ! identity::exists "$name"; then
25 log::error "Identity '${name}' not found. Use 'wgctl identity list' to see all identities."
26 return 1
27 fi
28}
29
30function identity::require_not_exists() {
31 local name="${1:-}"
32 if identity::exists "$name"; then
33 log::error "Identity '${name}' already exists."
34 return 1
35 fi
36}
37
38# identity::require_exists_for_flag <identity_name>
39# Used by commands to validate --identity value before proceeding.
40function identity::require_exists_for_flag() {
41 local identity_name="${1:-}"
42 [[ -z "$identity_name" ]] && {
43 log::error "Missing value for --identity"
44 return 1
45 }
46 # Identity may not exist yet for add (it will be created)
47 # Only require existence for commands that read from it
48 return 0
49}
50
51# identity::require_has_peers <identity_name>
52# Used by block/unblock/list to ensure identity has peers to operate on.
53function identity::require_has_peers() {
54 local identity_name="${1:-}"
55 local peers
56 peers=$(identity::peers "$identity_name")
57 if [[ -z "$peers" ]]; then
58 log::error "Identity '${identity_name}' has no peers"
59 return 1
60 fi
61}
62
63# ===========================================================================
64# Peer name inference
65# ===========================================================================
66
67# identity::infer <peer_name>
68# Parses a peer name and returns "identity_name|type|index" if it matches
69# the naming convention, or empty string if not.
70# phone-nuno -> "nuno|phone|1"
71# phone-nuno-2 -> "nuno|phone|2"
72# roboclean -> "" (no type prefix)
73function identity::infer() {
74 local peer_name="${1:-}"
75 json::identity_infer "$peer_name" 2>/dev/null || true
76}
77
78# identity::next_index <identity_name> <type>
79# Returns the next available device index for a type within an identity.
80# If identity doesn't exist yet, returns 1.
81function identity::next_index() {
82 local identity_name="${1:-}" peer_type="${2:-}"
83 local id_file
84 id_file=$(identity::path "$identity_name")
85 if [[ ! -f "$id_file" ]]; then
86 echo 1
87 return 0
88 fi
89 json::identity_next_index "$id_file" "$peer_type" 2>/dev/null || echo 1
90}
91
92# identity::next_peer_name <identity_name> <type>
93# Returns the full peer name for the next device of a given type
94# for an identity. Creates the name with the correct index.
95# e.g. identity::next_peer_name helena phone → phone-helena-2
96# (if phone-helena already exists, index 1 is taken)
97function identity::next_peer_name() {
98 local identity_name="${1:-}" peer_type="${2:-}"
99 [[ -z "$identity_name" || -z "$peer_type" ]] && return 1
100
101 local index
102 index=$(identity::next_index "$identity_name" "$peer_type")
103
104 if [[ "$index" -eq 1 ]]; then
105 echo "${peer_type}-${identity_name}"
106 else
107 echo "${peer_type}-${identity_name}-${index}"
108 fi
109}
110
111# ===========================================================================
112# Auto-attach (called from wgctl add)
113# ===========================================================================
114
115# identity::auto_attach <peer_name> <peer_type>
116# Infers identity from peer name and adds the peer to the identity file.
117# Creates the identity file if it doesn't exist.
118# Silent — no output. Logs a note on success, silently skips if no match.
119function identity::auto_attach() {
120 local peer_name="${1:-}" peer_type="${2:-}"
121 local inferred
122 inferred=$(identity::infer "$peer_name")
123 [[ -z "$inferred" ]] && return 0
124
125 local identity_name type_inferred index
126 identity_name=$(echo "$inferred" | cut -d'|' -f1)
127 type_inferred=$(echo "$inferred" | cut -d'|' -f2)
128 index=$(echo "$inferred" | cut -d'|' -f3)
129
130 # Use the explicit type if provided, otherwise use inferred type
131 local final_type="${peer_type:-$type_inferred}"
132
133 local id_file
134 id_file=$(identity::path "$identity_name")
135
136 json::identity_add_peer "$id_file" "$identity_name" "$peer_name" "$final_type" "$index" </dev/null
137 log::info "Attached '${peer_name}' to identity '${identity_name}' (${final_type} #${index})"
138}
139
140# identity::auto_detach <peer_name>
141# Removes a peer from its identity file when the peer is deleted.
142# If the identity has no remaining peers, removes the identity file too.
143function identity::auto_detach() {
144 local peer_name="${1:-}"
145 local inferred
146 inferred=$(identity::infer "$peer_name")
147 [[ -z "$inferred" ]] && return 0
148
149 local identity_name
150 identity_name=$(echo "$inferred" | cut -d'|' -f1)
151 local id_file
152 id_file=$(identity::path "$identity_name")
153 [[ ! -f "$id_file" ]] && return 0
154
155 json::identity_remove_peer "$id_file" "$peer_name" </dev/null
156
157 # Remove identity file if now empty
158 local remaining
159 remaining=$(json::identity_peers "$id_file" 2>/dev/null) || true
160 if [[ -z "$remaining" ]]; then
161 rm -f "$id_file"
162 log::info "Identity '${identity_name}' removed (no remaining peers)"
163 fi
164}
165
166# ===========================================================================
167# Peer queries
168# ===========================================================================
169
170# identity::peers <identity_name> [type_filter]
171# Returns peer names belonging to an identity, one per line.
172# Optional type_filter limits to peers of a specific type.
173function identity::peers() {
174 local identity_name="${1:-}" type_filter="${2:-}"
175 local id_file
176 id_file=$(identity::path "$identity_name")
177 json::identity_peers "$id_file" "$type_filter" 2>/dev/null || true
178}
179
180# identity::get_name <peer_name>
181# Returns the identity name for a given peer (via inference).
182function identity::get_name() {
183 local peer_name="${1:-}"
184 local inferred
185 inferred=$(identity::infer "$peer_name")
186 [[ -n "$inferred" ]] && echo "${inferred%%|*}"
187}
188
189# ===========================================================================
190# Data for commands
191# ===========================================================================
192
193function identity::list_data() {
194 json::identity_list "$(ctx::identities)" 2>/dev/null || true
195}
196
197function identity::show_data() {
198 local name="${1:-}"
199 json::identity_show "$(identity::path "$name")" 2>/dev/null
200}
201
202# ===========================================================================
203# Rename helper (called from rename.command.sh)
204# ===========================================================================
205
206# identity::rename_peer <old_peer_name> <new_peer_name>
207# Updates identity file entry when a peer is renamed.
208# Re-infers identity from old name, removes old entry, adds new entry.
209function identity::rename_peer() {
210 local old_name="${1:-}" new_name="${2:-}"
211
212 local old_inferred
213 old_inferred=$(identity::infer "$old_name")
214 [[ -z "$old_inferred" ]] && return 0
215
216 local identity_name old_type old_index
217 identity_name=$(echo "$old_inferred" | cut -d'|' -f1)
218 old_type=$(echo "$old_inferred" | cut -d'|' -f2)
219 old_index=$(echo "$old_inferred" | cut -d'|' -f3)
220
221 local id_file
222 id_file=$(identity::path "$identity_name")
223 [[ ! -f "$id_file" ]] && return 0
224
225 # Infer new identity context from new name
226 local new_inferred new_identity new_type new_index
227 new_inferred=$(identity::infer "$new_name")
228 if [[ -n "$new_inferred" ]]; then
229 new_identity=$(echo "$new_inferred" | cut -d'|' -f1)
230 new_type=$(echo "$new_inferred" | cut -d'|' -f2)
231 new_index=$(echo "$new_inferred" | cut -d'|' -f3)
232 else
233 # New name doesn't match convention — detach cleanly
234 json::identity_remove_peer "$id_file" "$old_name" </dev/null
235 return 0
236 fi
237
238 # Remove old entry
239 json::identity_remove_peer "$id_file" "$old_name" </dev/null
240
241 if [[ "$new_identity" == "$identity_name" ]]; then
242 # Same identity — update in place
243 json::identity_add_peer "$id_file" "$identity_name" "$new_name" "$new_type" "$new_index" </dev/null
244 else
245 # Identity changed (e.g. phone-nuno -> phone-helena) — move to new identity file
246 local new_id_file
247 new_id_file=$(identity::path "$new_identity")
248 json::identity_add_peer "$new_id_file" "$new_identity" "$new_name" "$new_type" "$new_index" </dev/null
249 # Clean up old identity if empty
250 local remaining
251 remaining=$(json::identity_peers "$id_file" 2>/dev/null) || true
252 if [[ -z "$remaining" ]]; then
253 rm -f "$id_file"
254 fi
255 fi
256}
257
258
259# identity::policy <identity_name>
260# Returns the policy name assigned to an identity, or "default".
261function identity::policy() {
262 local identity_name="${1:-}"
263 local id_file
264 id_file=$(ctx::identity::path "${identity_name}.identity")
265 [[ ! -f "$id_file" ]] && echo "default" && return 0
266 local result
267 result=$(json::get "$id_file" "policy" 2>/dev/null) || true
268 echo "${result:-default}"
269}
270
271# identity::set_policy <identity_name> <policy_name>
272# Sets the policy on an identity file.
273function identity::set_policy() {
274 local identity_name="${1:-}" policy_name="${2:-}"
275 local id_file
276 id_file=$(ctx::identity::path "${identity_name}.identity")
277 if [[ ! -f "$id_file" ]]; then
278 log::error "Identity '${identity_name}' not found"
279 return 1
280 fi
281 json::set "$id_file" "policy" "$policy_name"
282}
283
284# identity::rule_flags <identity_name> <flag>
285# Returns a specific rule_flag from the identity file.
286# Falls back to the policy's value if not explicitly set on the identity.
287function identity::rule_flags() {
288 local identity_name="${1:-}" flag="${2:-}"
289 local id_file
290 id_file=$(ctx::identity::path "${identity_name}.identity")
291
292 local result
293 result=$(json::get_nested "$id_file" "rule_flags" "$flag" 2>/dev/null) || true
294
295 if [[ -n "$result" ]]; then
296 echo "$result"
297 return 0
298 fi
299
300 # Fall back to policy value
301 local policy_name
302 policy_name=$(identity::policy "$identity_name")
303 policy::get "$policy_name" "$flag"
304}
305
306# identity::set_rule_flag <identity_name> <flag> <value>
307# Sets a rule_flag directly on the identity file.
308function identity::set_rule_flag() {
309 local identity_name="${1:-}" flag="${2:-}" value="${3:-}"
310 local id_file
311 id_file=$(ctx::identity::path "${identity_name}.identity")
312 if [[ ! -f "$id_file" ]]; then
313 log::error "Identity '${identity_name}' not found"
314 return 1
315 fi
316 json::set_nested "$id_file" "rule_flags" "$flag" "$value"
317}
318
319# identity::reapply_rules <identity_name>
320# Reapply the identity rule to all peers in this identity.
321# Respects auto_apply flag — if false, does nothing.
322function identity::reapply_rules() {
323 local identity_name="${1:-}"
324
325 # Check auto_apply
326 local auto
327 auto=$(identity::rule_flags "$identity_name" "auto_apply")
328 [[ "$auto" == "false" ]] && return 0
329
330 local identity_rule
331 identity_rule=$(identity::rule "$identity_name")
332 [[ -z "$identity_rule" ]] && return 0
333
334 local peers
335 peers=$(identity::peers "$identity_name")
336 [[ -z "$peers" ]] && return 0
337
338 while IFS= read -r peer_name; do
339 [[ -z "$peer_name" ]] && continue
340 local client_ip
341 client_ip=$(peers::get_ip "$peer_name") || continue
342 rule::full_restore_peer "$peer_name" "$client_ip"
343 done <<< "$peers"
344}
345
346# identity::rules <identity_name>
347# Returns all rules assigned to an identity, one per line.
348# Empty output if no rules assigned.
349function identity::rules() {
350 local identity_name="${1:-}"
351 local id_file
352 id_file=$(ctx::identity::path "${identity_name}.identity")
353 [[ ! -f "$id_file" ]] && return 0
354 json::identity_rules "$id_file" 2>/dev/null || true
355}
356
357# identity::has_rule <identity_name> <rule_name>
358# Returns 0 if identity has this rule, 1 otherwise.
359function identity::has_rule() {
360 local identity_name="${1:-}" rule_name="${2:-}"
361 local id_file
362 id_file=$(ctx::identity::path "${identity_name}.identity")
363 json::identity_has_rule "$id_file" "$rule_name" 2>/dev/null
364}
365
366# identity::add_rule <identity_name> <rule_name>
367# Adds a rule to an identity. Warns if already present (exit 2).
368function identity::add_rule() {
369 local identity_name="${1:-}" rule_name="${2:-}"
370 local id_file
371 id_file=$(ctx::identity::path "${identity_name}.identity")
372
373 local exit_code=0
374 json::identity_add_rule "$id_file" "$identity_name" "$rule_name" 2>/dev/null || exit_code=$?
375 return $exit_code
376}
377
378# identity::remove_rule <identity_name> <rule_name>
379# Removes a specific rule from an identity.
380function identity::remove_rule() {
381 local identity_name="${1:-}" rule_name="${2:-}"
382 local id_file
383 id_file=$(ctx::identity::path "${identity_name}.identity")
384 json::identity_remove_rule "$id_file" "$rule_name" 2>/dev/null
385}
386
387# identity::clear_rules <identity_name>
388# Removes all rules from an identity.
389function identity::clear_rules() {
390 local identity_name="${1:-}"
391 local id_file
392 id_file=$(ctx::identity::path "${identity_name}.identity")
393 json::identity_clear_rules "$id_file" 2>/dev/null
394}
395
396# identity::reapply_rules <identity_name>
397# Reapply all identity rules to all peers in this identity.
398# Respects auto_apply flag.
399function identity::reapply_rules() {
400 local identity_name="${1:-}"
401
402 local auto
403 auto=$(identity::rule_flags "$identity_name" "auto_apply")
404 [[ "$auto" == "false" ]] && return 0
405
406 local rules
407 rules=$(identity::rules "$identity_name")
408 [[ -z "$rules" ]] && return 0
409
410 local peers
411 peers=$(identity::peers "$identity_name")
412 [[ -z "$peers" ]] && return 0
413
414 while IFS= read -r peer_name; do
415 [[ -z "$peer_name" ]] && continue
416 local client_ip
417 client_ip=$(peers::get_ip "$peer_name") || continue
418 rule::full_restore_peer "$peer_name" "$client_ip"
419 done <<< "$peers"
420}