Последняя активность 1 month ago

Версия 6355494db28776b43c36b648868eaf7ea1c278e9

gistfile1.txt Исходник
1#!/usr/bin/env bash
2# ui/rule.module.sh — rendering for rule data
3# Replaces rule::render_* functions from rule.module.sh.
4# All functions pure rendering — no writes, no state changes.
5
6# ======================================================
7# Entry Rendering (shared primitives)
8# ======================================================
9
10# ui::rule::entries <rule_name> [indent]
11# Renders the fully resolved entries for a rule (allow + block).
12function ui::rule::entries() {
13 local rule_name="${1:-}" indent="${2:-4}"
14
15 local allow_ports allow_ips block_ips block_ports dns
16 allow_ports=$(rule::get "$rule_name" "allow_ports" 2>/dev/null || true)
17 allow_ips=$(rule::get "$rule_name" "allow_ips" 2>/dev/null || true)
18 block_ips=$(rule::get "$rule_name" "block_ips" 2>/dev/null || true)
19 block_ports=$(rule::get "$rule_name" "block_ports" 2>/dev/null || true)
20 dns=$(rule::get_own "$rule_name" "dns_redirect")
21
22 while IFS= read -r e; do
23 [[ -z "$e" ]] && continue
24 net::print_entry "+" "$e" "$indent"
25 done <<< "$allow_ports"$'\n'"$allow_ips"
26
27 while IFS= read -r e; do
28 [[ -z "$e" ]] && continue
29 net::print_entry "-" "$e" "$indent"
30 done <<< "$block_ips"$'\n'"$block_ports"
31
32 [[ "${dns,,}" == "true" ]] && \
33 net::print_dns_redirect "$(config::dns)" 6 "DNS"
34}
35
36# ui::rule::own_entries <rule_name> [indent]
37# Renders only the rule's own (non-inherited) entries.
38function ui::rule::own_entries() {
39 local rule_name="${1:-}" indent="${2:-4}"
40 local rule_file
41 rule_file="$(rule::path "$rule_name")" || return 0
42 [[ -z "$rule_file" ]] && return 0
43
44 local allow_ports allow_ips block_ips block_ports dns
45 allow_ports=$(json::get "$rule_file" "allow_ports" 2>/dev/null || true)
46 allow_ips=$(json::get "$rule_file" "allow_ips" 2>/dev/null || true)
47 block_ips=$(json::get "$rule_file" "block_ips" 2>/dev/null || true)
48 block_ports=$(json::get "$rule_file" "block_ports" 2>/dev/null || true)
49 dns=$(json::get "$rule_file" "dns_redirect" 2>/dev/null || true)
50
51 local combined="${allow_ports}${allow_ips}${block_ips}${block_ports}"
52 [[ -z "${combined//[$'\n']/}" ]] && return 0
53
54 while IFS= read -r e; do
55 [[ -z "$e" ]] && continue
56 net::print_entry "+" "$e" "$indent"
57 done <<< "$allow_ports"$'\n'"$allow_ips"
58
59 while IFS= read -r e; do
60 [[ -z "$e" ]] && continue
61 net::print_entry "-" "$e" "$indent"
62 done <<< "$block_ips"$'\n'"$block_ports"
63
64 [[ "${dns,,}" == "true" ]] && \
65 net::print_dns_redirect "$(config::dns)" 6 "DNS"
66}
67
68# ui::rule::flat <rule_name>
69# Renders the full resolved entries as a flat list.
70function ui::rule::flat() {
71 local rule_name="${1:-}"
72
73 local allow_ports allow_ips block_ips block_ports dns
74 allow_ports=$(rule::get "$rule_name" "allow_ports")
75 allow_ips=$(rule::get "$rule_name" "allow_ips")
76 block_ips=$(rule::get "$rule_name" "block_ips")
77 block_ports=$(rule::get "$rule_name" "block_ports")
78 dns=$(rule::get_own "$rule_name" "dns_redirect")
79
80 local has_content=false
81 [[ -n "${allow_ports}${allow_ips}${block_ips}${block_ports}" ]] && has_content=true
82
83 if ! $has_content; then
84 printf "\n full access (no restrictions)\n"
85 return 0
86 fi
87
88 if [[ -n "$allow_ports" || -n "$allow_ips" ]]; then
89 printf "\n"
90 while IFS= read -r e; do
91 [[ -z "$e" ]] && continue
92 net::print_entry "+" "$e" 2
93 done <<< "$allow_ports"$'\n'"$allow_ips"
94 fi
95
96 if [[ -n "$block_ips" || -n "$block_ports" ]]; then
97 printf "\n"
98 while IFS= read -r e; do
99 [[ -z "$e" ]] && continue
100 net::print_entry "-" "$e" 2
101 done <<< "$block_ips"$'\n'"$block_ports"
102 fi
103
104 [[ "${dns,,}" == "true" ]] && \
105 net::print_dns_redirect "$(config::dns)" 6 "DNS"
106}
107
108# ======================================================
109# Shared Base Renderer
110# ======================================================
111
112# ui::rule::_render_bases <array_nameref> [entry_indent] [label_indent]
113# Renders a list of base rule names with newlines between them.
114# Used by both ui::rule::tree and ui::rule::_identity_rule_entry.
115function ui::rule::_render_bases() {
116 local -n _bases="$1"
117 local entry_indent="${2:-6}" label_indent="${3:-4}"
118 local label_pad
119 label_pad=$(printf '%*s' "$label_indent" '')
120
121 local first=true
122 for base_name in "${_bases[@]}"; do
123 [[ -z "$base_name" ]] && continue
124 $first || printf "\n"
125 first=false
126 printf "%s\033[0;37m↳ %s\033[0m\n" "$label_pad" "$base_name"
127 ui::rule::entries "$base_name" "$entry_indent"
128 done
129}
130
131# ======================================================
132# Tree Rendering
133# ======================================================
134
135# ui::rule::tree <rule_name>
136# Renders a rule's extends tree — one level deep with own entries.
137# Returns 1 if rule has no extends (caller can fall back to flat).
138function ui::rule::tree() {
139 local rule_name="${1:-}"
140 local rule_file
141 rule_file="$(rule::path "$rule_name")" || return 1
142 [[ -z "$rule_file" ]] && return 1
143
144 local extends_raw=()
145 mapfile -t extends_raw < <(json::get "$rule_file" "extends" 2>/dev/null || true) || true
146
147 if [[ ${#extends_raw[@]} -eq 0 || -z "${extends_raw[0]:-}" ]]; then
148 return 1
149 fi
150
151 ui::rule::_render_bases extends_raw 6 4
152
153 local own_output
154 own_output=$(ui::rule::own_entries "$rule_name" 6)
155 if [[ -n "$own_output" ]]; then
156 printf "\n \033[0;37mOwn:\033[0m\n"
157 printf "%s\n" "$own_output"
158 fi
159
160 return 0
161}
162
163# ======================================================
164# Identity Rule Block
165# ======================================================
166
167# ui::rule::identity_block <identity_name> <strict_rule>
168# Renders the full identity rule block in inspect.
169function ui::rule::identity_block() {
170 local identity_name="${1:-}" strict="${2:-false}" no_header=false
171
172 # Parse optional flags
173 shift 2 || true
174 while [[ $# -gt 0 ]]; do
175 case "$1" in
176 --no-header) no_header=true; shift ;;
177 *) shift ;;
178 esac
179 done
180
181 local rules
182 rules=$(identity::rules "$identity_name")
183 [[ -z "$rules" ]] && return 0
184
185 if ! $no_header; then
186 printf "\n \033[0;37m· identity:%s\033[0m\n" "$identity_name"
187 fi
188
189 # Indentation levels:
190 # normal: entry=6 label=6 own=10 own_label=8
191 # no-header: entry=4 label=4 own=8 own_label=6
192 local entry_indent label_indent own_indent own_label_indent
193 if $no_header; then
194 entry_indent=4
195 label_indent=4
196 own_indent=8
197 own_label_indent=6
198 else
199 entry_indent=6
200 label_indent=6
201 own_indent=10
202 own_label_indent=8
203 fi
204
205 local first=true
206 while IFS= read -r rule_name; do
207 [[ -z "$rule_name" ]] && continue
208 $first || printf "\n"
209 first=false
210 ui::rule::_identity_rule_entry "$rule_name" \
211 "$entry_indent" "$label_indent" "$own_indent" "$own_label_indent"
212 done <<< "$rules"
213
214 if [[ "$strict" == "true" ]]; then
215 printf "\n \033[2m(strict — peer rule suppressed)\033[0m\n"
216 fi
217}
218
219# ui::rule::_identity_rule_entry <rule_name>
220# Renders one rule within an identity block.
221function ui::rule::_identity_rule_entry() {
222 local rule_name="${1:-}"
223 local entry_indent="${2:-6}"
224 local label_indent="${3:-6}"
225 local own_indent="${4:-10}"
226 local own_label_indent="${5:-8}"
227
228 local rule_file
229 rule_file="$(rule::path "$rule_name")" || return 0
230
231 local label_pad
232 label_pad=$(printf '%*s' "$label_indent" '')
233 printf "%s\033[0;37m↳ %s\033[0m\n" "$label_pad" "$rule_name"
234
235 local extends_raw=()
236 mapfile -t extends_raw < <(json::get "$rule_file" "extends" 2>/dev/null || true) || true
237
238 if [[ ${#extends_raw[@]} -gt 0 && -n "${extends_raw[0]:-}" ]]; then
239 ui::rule::_render_bases extends_raw "$own_indent" "$(( entry_indent + 2 ))"
240
241 local own_output
242 own_output=$(ui::rule::own_entries "$rule_name" "$own_indent")
243 if [[ -n "$own_output" ]]; then
244 local own_pad
245 own_pad=$(printf '%*s' "$(( entry_indent + 2 ))" '')
246 printf "\n%s\033[0;37mOwn:\033[0m\n" "$own_pad"
247 printf "%s\n" "$own_output"
248 fi
249 else
250 local own_output
251 own_output=$(ui::rule::own_entries "$rule_name" "$entry_indent")
252 if [[ -n "$own_output" ]]; then
253 printf "%s\n" "$own_output"
254 else
255 local full_pad
256 full_pad=$(printf '%*s' "$(( entry_indent + 2 ))" '')
257 printf "%s\033[2mfull access (no restrictions)\033[0m\n" "$full_pad"
258 fi
259 fi
260}
261
262# ======================================================
263# Peer Entry
264# ======================================================
265
266function ui::rule::_peer_rule_entry() {
267 local rule_name="${1:-}"
268 local rule_file
269 rule_file="$(rule::path "$rule_name")" || return 0
270
271 printf " \033[0;37m↳ %s\033[0m\n" "$rule_name"
272
273 local extends_raw=()
274 mapfile -t extends_raw < <(json::get "$rule_file" "extends" 2>/dev/null || true) || true
275
276 if [[ ${#extends_raw[@]} -gt 0 && -n "${extends_raw[0]:-}" ]]; then
277 ui::rule::_render_bases extends_raw 10 8
278
279 local own_output
280 own_output=$(ui::rule::own_entries "$rule_name" 10)
281 if [[ -n "$own_output" ]]; then
282 printf "\n \033[0;37mOwn:\033[0m\n"
283 printf "%s\n" "$own_output"
284 fi
285 else
286 local own_output
287 own_output=$(ui::rule::own_entries "$rule_name" 8)
288 if [[ -n "$own_output" ]]; then
289 printf "%s\n" "$own_output"
290 else
291 printf " \033[2mfull access (no restrictions)\033[0m\n"
292 fi
293 fi
294}
295
296# ======================================================
297# List Rendering
298# ======================================================
299
300# ui::rule::list_group_header <group_name>
301function ui::rule::list_group_header() {
302 local group="${1:-}"
303 printf "\n \033[0;36m▸ %s\033[0m\n" "$group"
304}
305
306# ui::rule::list_base_header
307function ui::rule::list_base_header() {
308 printf "\n \033[2m── Base Rules ──────────────────────\033[0m\n"
309}
310
311
312# ui::rule::list_row <name> <n_allows> <n_blocks> <peer_count> <w_name>
313function ui::rule::list_row() {
314 local name="${1:-}" n_allows="${2:-0}" n_blocks="${3:-0}" \
315 peer_count="${4:-0}" w_name="${5:-16}" extends_csv="${6:-}"
316
317 local name_pad
318 name_pad=$(printf "%-${w_name}s" "$name")
319
320 local peer_word="peers"
321 [[ "$peer_count" -eq 1 ]] && peer_word="peer"
322
323 local peers_display
324 peers_display=$(printf "%s %s" "$peer_count" "$peer_word")
325 local peers_pad_n=$(( 10 - ${#peers_display} ))
326 [[ $peers_pad_n -lt 0 ]] && peers_pad_n=0
327
328 local extends_indicator=""
329 if [[ -n "$extends_csv" ]]; then
330 local extends_display="${extends_csv//,/, }"
331 extends_indicator=" \033[2m↳ ${extends_display}\033[0m"
332 fi
333
334 # Allows column — green +N if >0, dim +0 if zero
335 local allows_str
336 if [[ "$n_allows" -gt 0 ]]; then
337 allows_str=$(ui::pad_mb "\033[1;32m+${n_allows}\033[0m" 5)
338 else
339 allows_str=$(ui::pad_mb "\033[2m+0\033[0m" 5)
340 fi
341
342 # Blocks column — red -N if >0, dim -0 if zero
343 local blocks_str
344 if [[ "$n_blocks" -gt 0 ]]; then
345 blocks_str=$(ui::pad_mb "\033[1;31m-${n_blocks}\033[0m" 5)
346 else
347 blocks_str=$(ui::pad_mb "\033[2m-0\033[0m" 5)
348 fi
349
350 # Peers — dim if zero
351 local peers_colored
352 if [[ "$peer_count" -eq 0 ]]; then
353 peers_colored="\033[2m${peers_display}\033[0m"
354 else
355 peers_colored="$peers_display"
356 fi
357
358 printf " %s %b%b %b%*s%b\n" \
359 "$name_pad" "$allows_str" "$blocks_str" \
360 "$peers_colored" "$peers_pad_n" "" "$extends_indicator"
361}
362
363# ui::rule::list_extends <extends_csv>
364# Renders the extends tree for a rule in list view (compact, one level)
365function ui::rule::list_extends() {
366 local extends_csv="${1:-}"
367 [[ -z "$extends_csv" ]] && return 0
368
369 local extend_list=()
370 IFS=',' read -ra extend_list <<< "$extends_csv"
371 for base in "${extend_list[@]}"; do
372 [[ -z "$base" ]] && continue
373 printf " \033[0;37m ↳ %s\033[0m\n" "$base"
374 done
375}
376
377# ui::rule::list_extends_detailed <extends_csv> <rules_dir>
378# Renders the extends tree with entries expanded (--detailed mode)
379function ui::rule::list_extends_detailed() {
380 local extends_csv="${1:-}" rules_dir="${2:-}"
381 [[ -z "$extends_csv" ]] && return 0
382
383 local extend_list=()
384 IFS=',' read -ra extend_list <<< "$extends_csv"
385 for base in "${extend_list[@]}"; do
386 [[ -z "$base" ]] && continue
387 printf " \033[0;37m ↳ %s\033[0m\n" "$base"
388 ui::rule::entries "$base" 6
389 done
390}
391
392# ======================================================
393# Show helpers
394# ======================================================
395
396function ui::rule::section_header() {
397 local title="${1:-}"
398 printf "\n \033[0;37m── %s ──────────────────────────────────\033[0m\n" "$title"
399}