Naposledy aktivní 1 month ago

nuno revidoval tento gist 1 month ago. Přejít na revizi

1 file changed, 420 insertions

gistfile1.txt(vytvořil soubor)

@@ -0,0 +1,420 @@
1 + #!/usr/bin/env bash
2 + # identity.module.sh — identity file management and peer-name inference
3 +
4 + # ===========================================================================
5 + # Path helpers
6 + # ===========================================================================
7 +
8 + function identity::path() {
9 + local name="${1:-}"
10 + echo "$(ctx::identities)/${name}.identity"
11 + }
12 +
13 + # ===========================================================================
14 + # Existence checks
15 + # ===========================================================================
16 +
17 + function identity::exists() {
18 + local name="${1:-}"
19 + json::identity_exists "$(identity::path "$name")" 2>/dev/null
20 + }
21 +
22 + function 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 +
30 + function 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.
40 + function 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.
53 + function 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)
73 + function 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.
81 + function 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)
97 + function 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.
119 + function 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.
143 + function 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.
173 + function 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).
182 + function 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 +
193 + function identity::list_data() {
194 + json::identity_list "$(ctx::identities)" 2>/dev/null || true
195 + }
196 +
197 + function 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.
209 + function 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".
261 + function 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.
273 + function 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.
287 + function 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.
308 + function 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.
322 + function 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.
349 + function 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.
359 + function 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).
368 + function 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.
380 + function 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.
389 + function 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.
399 + function 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 + }
Novější Starší