Son aktivite 1 month ago

nuno bu gisti düzenledi 1 month ago. Düzenlemeye git

1 file changed, 588 insertions

gistfile1.txt(dosya oluşturuldu)

@@ -0,0 +1,588 @@
1 + #!/usr/bin/env bash
2 +
3 + # ============================================
4 + # Client Config
5 + # ============================================
6 +
7 + function peers::create_client_config() {
8 + local name="$1"
9 + local type="$2"
10 + local ip="$3"
11 + local allowed_ips="${4:-$(config::allowed_ips_for "split")}"
12 +
13 + local conf
14 + conf="$(ctx::clients)/${name}.conf"
15 +
16 + if [[ -f "$conf" ]]; then
17 + log::wg_warning "Client config already exists: ${name}"
18 + return 1
19 + fi
20 +
21 + local private_key
22 + private_key=$(keys::private "$name")
23 +
24 + local server_public_key
25 + server_public_key=$(config::server_public_key)
26 +
27 + cat > "$conf" <<EOF
28 + [Interface]
29 + PrivateKey = ${private_key}
30 + Address = ${ip}/32
31 + DNS = $(config::dns)
32 +
33 + [Peer]
34 + PublicKey = ${server_public_key}
35 + Endpoint = $(config::endpoint)
36 + AllowedIPs = ${allowed_ips}
37 + PersistentKeepalive = 25
38 + EOF
39 +
40 + chmod 600 "$conf"
41 + log::debug "Created client config: ${name} (${ip})"
42 + }
43 +
44 + function peers::remove_client_config() {
45 + local name="$1"
46 + local conf
47 + conf="$(ctx::clients)/${name}.conf"
48 +
49 + if [[ ! -f "$conf" ]]; then
50 + log::wg_warning "Client config not found: ${name}"
51 + return 1
52 + fi
53 +
54 + rm -f "$conf"
55 + log::debug "Removed client config: ${name}"
56 + }
57 +
58 + # ============================================
59 + # Server Config (wg0.conf) Peer Management
60 + # ============================================
61 +
62 + function peers::cleanup_config() {
63 + json::cleanup_config "$(config::config_file)"
64 + }
65 +
66 +
67 + function peers::add_to_server() {
68 + local name="${1:?name required}"
69 + local public_key="${2:?public_key required}"
70 + local ip="${3:?ip required}"
71 +
72 + local config
73 + config=$(config::config_file)
74 +
75 + cat >> "$config" <<EOF
76 +
77 + [Peer]
78 + # ${name}
79 + PublicKey = ${public_key}
80 + AllowedIPs = ${ip}/32
81 + EOF
82 +
83 + log::debug "Added peer to server config: ${name}"
84 + }
85 +
86 + function peers::remove_block() {
87 + local name="${1:?name required}"
88 + json::remove_peer_block "$(config::config_file)" "$name"
89 + }
90 +
91 + function peers::remove_from_server() {
92 + local name="${1:?name required}"
93 + peers::remove_block "$name"
94 + peers::cleanup_config
95 + log::debug "Removed peer from server config: ${name}"
96 + }
97 +
98 + # ============================================
99 + # Listing
100 + # ============================================
101 +
102 + function peers::list() {
103 + local dir
104 + dir="$(ctx::clients)"
105 +
106 + if [[ -z "$(ls -A "$dir"/*.conf 2>/dev/null)" ]]; then
107 + log::wg_list "No clients configured"
108 + return 0
109 + fi
110 +
111 + for conf in "${dir}"/*.conf; do
112 + local client_name
113 + client_name=$(basename "$conf" .conf)
114 +
115 + local ip
116 + ip=$(grep "^Address" "$conf" | awk '{print $3}' | cut -d'/' -f1)
117 +
118 + local public_key
119 + public_key=$(keys::public "$client_name" 2>/dev/null || echo "unknown")
120 +
121 + # Determine type from IP
122 + local type="unknown"
123 + for t in $(config::device_types); do
124 + local subnet
125 + subnet=$(config::subnet_for "$t")
126 + if string::starts_with "$ip" "$subnet"; then
127 + type="$t"
128 + break
129 + fi
130 + done
131 +
132 + printf " %-30s %-15s %-10s %s\n" \
133 + "$client_name" "$ip" "$type" "$public_key"
134 + done
135 + }
136 +
137 + function peers::list_by_type() {
138 + local filter_type="$1"
139 + local dir
140 + dir="$(ctx::clients)"
141 +
142 + for conf in "${dir}"/*.conf; do
143 + local client_name
144 + client_name=$(basename "$conf" .conf)
145 +
146 + local ip
147 + ip=$(grep "^Address" "$conf" | awk '{print $3}' | cut -d'/' -f1)
148 +
149 + local subnet
150 + subnet=$(config::subnet_for "$filter_type")
151 +
152 + if string::starts_with "$ip" "$subnet"; then
153 + printf " %-30s %-15s\n" "$client_name" "$ip"
154 + fi
155 + done
156 + }
157 +
158 + function peers::exists_in_server() {
159 + local name="$1"
160 + grep -q "^# ${name}$" "$(config::config_file)"
161 + }
162 +
163 + # function peers::is_blocked() {
164 + # local name="${1:-}"
165 + # peers::exists_in_server "$name" && return 1 || return 0
166 + # }
167 +
168 + function peers::is_blocked() {
169 + local name="${1:-}"
170 + block::is_blocked "$name"
171 + }
172 +
173 + function peers::is_restricted() {
174 + local name="${1:-}"
175 + block::has_specific_rules "$name" 2>/dev/null
176 + }
177 +
178 + # ============================================
179 + # Default Rule
180 + # ============================================
181 +
182 + function peers::get_type() {
183 + local name="$1"
184 + local ip
185 + ip=$(peers::get_ip "$name")
186 + [[ -z "$ip" ]] && echo "unknown" && return 0
187 + peers::get_type_from_ip "$ip"
188 + }
189 +
190 + function peers::default_rule() {
191 + echo "user"
192 + }
193 +
194 + function peers::effective_rule() {
195 + local name="$1"
196 + local rule
197 + rule=$(peers::get_meta "$name" "rule")
198 + echo "${rule:---}"
199 + }
200 +
201 + # ============================================
202 + # Query
203 + # ============================================
204 +
205 + function peers::all() {
206 + local dir
207 + dir="$(ctx::clients)"
208 + for conf in "${dir}"/*.conf; do
209 + [[ -f "$conf" ]] || continue
210 + basename "$conf" .conf
211 + done
212 + }
213 +
214 + function peers::with_rule() {
215 + local rule="$1"
216 + while IFS= read -r name; do
217 + local effective
218 + effective=$(peers::effective_rule "$name")
219 + [[ "$effective" == "$rule" ]] && echo "$name"
220 + done < <(peers::all)
221 + }
222 +
223 + function peers::get_ip() {
224 + local name="$1"
225 + grep "^Address" "$(ctx::clients)/${name}.conf" 2>/dev/null \
226 + | awk '{print $3}' | cut -d'/' -f1 || true
227 + }
228 +
229 + function peers::find_by_ip() {
230 + local target_ip="$1"
231 + while IFS= read -r name; do
232 + local ip
233 + ip=$(peers::get_ip "$name")
234 + [[ "$ip" == "$target_ip" ]] && echo "$name" && return 0
235 + done < <(peers::all)
236 + }
237 +
238 + function peers::is_connected() {
239 + local handshake_ts="${1:-0}"
240 + local now diff threshold
241 + now=$(date +%s)
242 + threshold=$(config::handshake_time_sec)
243 + [[ "$handshake_ts" == "0" || -z "$handshake_ts" ]] && return 1
244 + diff=$(( now - handshake_ts ))
245 + (( diff < threshold ))
246 + }
247 +
248 + function peers::is_attempting() {
249 + local last_ts="${1:-}"
250 + [[ -z "$last_ts" ]] && return 1
251 + local now attempt_ts diff threshold
252 + now=$(date +%s)
253 + threshold=$(config::handshake_time_sec)
254 + attempt_ts=$(json::iso_to_ts "$last_ts")
255 + [[ -z "$attempt_ts" || "$attempt_ts" == "0" ]] && return 1
256 + diff=$(( now - attempt_ts ))
257 + (( diff < threshold ))
258 + }
259 +
260 + function peers::is_online() {
261 + local name="${1:-}" handshake_ts="${2:-0}" last_ts="${3:-}"
262 + local is_blocked
263 + peers::is_blocked "$name" && is_blocked="true" || is_blocked="false"
264 + if [[ "$is_blocked" == "true" ]]; then
265 + peers::is_attempting "$last_ts"
266 + else
267 + peers::is_connected "$handshake_ts"
268 + fi
269 + }
270 +
271 + function peers::is_offline() {
272 + local name="${1:-}" handshake_ts="${2:-0}" last_ts="${3:-}"
273 + peers::is_online "$name" "$handshake_ts" "$last_ts" && return 1 || return 0
274 + }
275 +
276 + function peers::get_main_group() {
277 + local name="${1:?}"
278 + peers::get_meta "$name" "main_group"
279 + }
280 +
281 + function peers::set_main_group() {
282 + local name="${1:?}" group="${2:?}"
283 + peers::set_meta "$name" "main_group" "$group"
284 + }
285 +
286 + # ============================================
287 + # Name + Type Parsing
288 + # ============================================
289 +
290 + function peers::resolve_name() {
291 + local name="$1"
292 + local type="${2:-}"
293 +
294 + if [[ -n "$type" ]]; then
295 + if ! subnet::exists "$type"; then
296 + log::error "Invalid device type: ${type}"
297 + return 1
298 + fi
299 + echo "${type}-${name}"
300 + else
301 + echo "$name"
302 + fi
303 + }
304 +
305 + function peers::require_exists() {
306 + local name="$1"
307 + if [[ ! -f "$(ctx::clients)/${name}.conf" ]]; then
308 + log::error "Client not found: ${name}"
309 + return 1
310 + fi
311 + }
312 +
313 + function peers::resolve_and_require() {
314 + local name="$1"
315 + local type="${2:-}"
316 +
317 + local resolved
318 + resolved=$(peers::resolve_name "$name" "$type") || return 1
319 + peers::require_exists "$resolved" || return 1
320 + echo "$resolved"
321 + }
322 +
323 + function peers::rename_meta() {
324 + local name="${1:-}" new_name="${2:-}"
325 + local old_meta new_meta
326 + old_meta=$(peers::meta_path "$name")
327 + new_meta=$(peers::meta_path "$new_name")
328 + [[ -f "$old_meta" ]] && mv "$old_meta" "$new_meta"
329 + return 0
330 + }
331 +
332 + # ============================================
333 + # Cleanup
334 + # ============================================
335 +
336 + function peers::purge() {
337 + local name="${1:-}" client_ip="${2:-}" was_blocked="${3:-false}"
338 +
339 + [[ -n "$client_ip" ]] && fw::flush_peer "$client_ip"
340 + peers::remove_from_server "$name" || return 1
341 + peers::remove_client_config "$name" || return 1
342 + keys::remove "$name" || return 1
343 + group::remove_peer_from_all "$name" || return 1
344 +
345 + if [[ -n "$client_ip" ]] && $was_blocked; then
346 + fw::unblock_all "$client_ip"
347 + fi
348 +
349 + block::remove_file "$name" 2>/dev/null || true
350 + peers::remove_meta "$name" 2>/dev/null || true
351 + peers::reload || return 1
352 + }
353 +
354 +
355 + # ============================================
356 + # Display / Formatting
357 + # ============================================
358 +
359 + function peers::format_last_seen() {
360 + local name="${1:-}" pubkey="${2:-}" is_blocked="${3:-false}"
361 + local last_ts="${4:-}" last_evt="${5:-}" handshake_ts="${6:-0}"
362 +
363 + local data
364 + data=$(peers::last_seen_data "$is_blocked" "$last_ts" "$handshake_ts")
365 +
366 + local ts type
367 + IFS="|" read -r ts type <<< "$data"
368 +
369 + case "$type" in
370 + none) echo "—" ;;
371 + dropped) echo "$(fmt::datetime_iso "$ts") (dropped)" ;;
372 + handshake) echo "$(fmt::datetime "$ts") (handshake)" ;;
373 + esac
374 + }
375 +
376 + # function peers::format_status() {
377 + # local name="${1:-}" public_key="${2:-}" is_blocked="${3:-false}"
378 + # local is_restricted="${4:-false}" handshake_ts="${5:-0}" last_ts="${6:-}"
379 +
380 + # local state
381 + # state=$(peers::connection_state "$is_blocked" "$is_restricted" \
382 + # "$handshake_ts" "$last_ts")
383 +
384 + # local conn_str modifier color
385 + # IFS="|" read -r conn_str modifier color <<< "$state"
386 +
387 + # local display="$conn_str"
388 + # [[ -n "$modifier" ]] && display="${conn_str} (${modifier})"
389 + # echo -e "${color}${display}\033[0m"
390 + # }
391 +
392 + function peers::format_status() {
393 + local name="${1:-}" public_key="${2:-}" is_blocked="${3:-false}"
394 + local is_restricted="${4:-false}" handshake_ts="${5:-0}" last_ts="${6:-}"
395 +
396 + local state
397 + state=$(peers::connection_state "$is_blocked" "$is_restricted" \
398 + "$handshake_ts" "$last_ts")
399 +
400 + local conn_str modifier color
401 + IFS="|" read -r conn_str modifier color <<< "$state"
402 +
403 + # Color based on state — modifier overrides base connection color
404 + if [[ "$is_blocked" == "true" ]]; then
405 + color="\033[1;31m" # red — blocked
406 + elif [[ "$is_restricted" == "true" ]]; then
407 + color="\033[1;33m" # yellow — restricted
408 + elif [[ "$conn_str" == "online" ]]; then
409 + color="\033[1;32m" # green — online
410 + else
411 + color="\033[0;37m" # gray — offline
412 + fi
413 +
414 + local conn_str_padded
415 + conn_str_padded=$(printf "%-7s" "$conn_str")
416 + echo -e "${color}${conn_str_padded}\033[0m"
417 + }
418 +
419 + # Inspect — verbose, color + descriptive text
420 + function peers::format_status_verbose() {
421 + local name="${1:-}" public_key="${2:-}" is_blocked="${3:-false}"
422 + local is_restricted="${4:-false}" handshake_ts="${5:-0}" last_ts="${6:-}"
423 +
424 + local conn_str
425 + local state
426 + state=$(peers::connection_state "$is_blocked" "$is_restricted" \
427 + "$handshake_ts" "$last_ts")
428 + IFS="|" read -r conn_str _ _ <<< "$state"
429 +
430 + local color suffix=""
431 + if [[ "$is_blocked" == "true" ]]; then
432 + color="\033[1;31m"
433 + suffix=" (blocked)"
434 + elif [[ "$is_restricted" == "true" ]]; then
435 + color="\033[1;33m"
436 + suffix=" (restricted)"
437 + elif [[ "$conn_str" == "online" ]]; then
438 + color="\033[1;32m"
439 + else
440 + color="\033[0;37m"
441 + fi
442 +
443 + echo -e "${color}${conn_str}${suffix}\033[0m"
444 + }
445 +
446 + function peers::display_type() {
447 + local type="${1:-}" _subtype="${2:-}"
448 + echo "${type:-unknown}"
449 + }
450 +
451 + # ============================================
452 + # Connection data
453 + # ============================================
454 +
455 + # Data functions — return raw values
456 + function peers::connection_state() {
457 + # Returns: connected|modifier|color_code
458 + local is_blocked="${1:-false}" is_restricted="${2:-false}"
459 + local handshake_ts="${3:-0}" last_ts="${4:-}"
460 + local threshold
461 + threshold=$(config::handshake_time_sec)
462 + local now
463 + now=$(date +%s)
464 + local connected=false modifier="" color
465 +
466 + if [[ "$is_blocked" == "true" ]]; then
467 + local attempt_ts diff
468 + attempt_ts=$(json::iso_to_ts "${last_ts:-0}")
469 + diff=$(( now - attempt_ts ))
470 + (( diff < threshold )) && connected=true
471 + modifier="blocked"
472 + color="\033[1;31m"
473 + elif [[ "$is_restricted" == "true" ]]; then
474 + local diff=$(( now - handshake_ts ))
475 + (( diff < threshold )) && connected=true
476 + modifier="restricted"
477 + color="\033[1;33m"
478 + else
479 + local diff=$(( now - handshake_ts ))
480 + (( diff < threshold )) && connected=true
481 + $connected && color="\033[1;32m" || color="\033[0;37m"
482 + fi
483 +
484 + $connected && echo "online|${modifier}|${color}" || echo "offline|${modifier}|${color}"
485 + }
486 +
487 + function peers::last_seen_data() {
488 + # Returns: timestamp|type (dropped|handshake|none)
489 + local is_blocked="${1:-false}" last_ts="${2:-}" handshake_ts="${3:-0}"
490 +
491 + if [[ "$is_blocked" == "true" ]]; then
492 + if [[ -n "$last_ts" && "$last_ts" != "0" && "$last_ts" != "null" ]]; then
493 + echo "${last_ts}|dropped"
494 + else
495 + echo "|none"
496 + fi
497 + else
498 + if [[ -z "$handshake_ts" || "$handshake_ts" == "0" ]]; then
499 + echo "|none"
500 + else
501 + echo "${handshake_ts}|handshake"
502 + fi
503 + fi
504 + }
505 +
506 + function peers::get_type_from_ip() {
507 + local ip="${1:-}"
508 + [[ -z "$ip" ]] && echo "unknown" && return 0
509 + subnet::type_from_ip "$ip"
510 + }
511 +
512 +
513 + # ============================================
514 + # Activity
515 + # ============================================
516 +
517 + # Returns: level|rx|tx
518 + function peers::activity_total() {
519 + local pubkey="${1:-}"
520 + json::peer_transfer "$(config::interface)" | grep "^${pubkey}" | head -1 | cut -d'|' -f2-
521 + }
522 +
523 + # Returns: level|rx_rate|tx_rate
524 + function peers::activity_current() {
525 + local pubkey="${1:-}"
526 + json::peer_transfer_delta "$(config::interface)" \
527 + "$(ctx::daemon)/transfer_cache.json" \
528 + | grep "^${pubkey}" | head -1 | cut -d'|' -f2-
529 + }
530 +
531 + function peers::format_activity_total() {
532 + local pubkey="${1:-}"
533 + local data
534 + data=$(peers::activity_total "$pubkey")
535 + [[ -z "$data" ]] && echo "—" && return 0
536 + local level rx tx rx_hr tx_hr
537 + IFS="|" read -r rx tx level <<< "$data"
538 + rx_hr=$(numfmt --to=iec "${rx:-0}" 2>/dev/null || echo "0B")
539 + tx_hr=$(numfmt --to=iec "${tx:-0}" 2>/dev/null || echo "0B")
540 + echo "${level:-none} (↓${rx_hr} ↑${tx_hr})"
541 + }
542 +
543 + function peers::format_activity_current() {
544 + local pubkey="${1:-}"
545 + local data
546 + data=$(peers::activity_current "$pubkey")
547 + [[ -z "$data" ]] && echo "—" && return 0
548 + local level rx_rate tx_rate rx_hr tx_hr
549 + IFS="|" read -r rx_rate tx_rate level <<< "$data"
550 + [[ "$level" == "unknown" ]] && echo "sampling..." && return 0
551 + local rx_hr tx_hr
552 + rx_hr=$(numfmt --to=iec "${rx_rate:-0}" 2>/dev/null || echo "${rx_rate:-0}")
553 + tx_hr=$(numfmt --to=iec "${tx_rate:-0}" 2>/dev/null || echo "${tx_rate:-0}")
554 + echo "${level} (↓${rx_hr}B/s ↑${tx_hr}B/s)"
555 + }
556 +
557 + # ============================================
558 + # Helpers - Meta File
559 + # ============================================
560 +
561 + function peers::meta_path() {
562 + local name="$1"
563 + echo "$(ctx::meta)/${name}.meta"
564 + }
565 +
566 + function peers::get_meta() {
567 + local name="$1" key="$2"
568 + json::get "$(peers::meta_path "$name")" "$key"
569 + }
570 +
571 + function peers::set_meta() {
572 + local name="$1" key="$2" value="$3"
573 + json::set "$(peers::meta_path "$name")" "$key" "$value"
574 + }
575 +
576 + function peers::remove_meta() {
577 + local name="$1"
578 + rm -f "$(peers::meta_path "$name")"
579 + }
580 +
581 + # ============================================
582 + # Live Reload
583 + # ============================================
584 +
585 + function peers::reload() {
586 + wg syncconf "$(config::interface)" <(wg-quick strip "$(config::interface)")
587 + log::debug "WireGuard config reloaded"
588 + }
Daha yeni Daha eski