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

gistfile1.txt Исходник
1function cmd::add::run() {
2 local name=""
3 local type=""
4 local subtype=""
5 local rule=""
6 local ip=""
7 local tunnel=""
8 local guest=false
9 local presets=()
10 local show_config=false
11 local show_qr=false
12
13 # Parse flags
14 while [[ $# -gt 0 ]]; do
15 case "$1" in
16 --name) name="$2"; shift 2 ;;
17 --type) type="$2"; shift 2 ;;
18 --subtype) subtype="$2"; shift 2 ;;
19 --rule) rule="$2"; shift 2 ;;
20 --ip) ip="$2"; shift 2 ;;
21 --preset) presets+=("$2"); shift 2 ;;
22 --guest) guest=true; shift ;;
23 --tunnel) tunnel="$2"; shift 2 ;;
24 --show-config) show_config=true; shift ;;
25 --show-qr) show_qr=true; shift ;;
26 --help) cmd::add::help; return ;;
27 *)
28 log::error "Unknown flag: $1"
29 cmd::add::help
30 return 1
31 ;;
32 esac
33 done
34
35 # --guest shorthand
36 if $guest; then
37 type="guest"
38 fi
39
40 # Resolve guest subtype
41 local effective_type="$type"
42 if [[ "$type" == "guest" && -n "$subtype" ]]; then
43 # Validate subtype
44 local valid_subtypes="desktop laptop phone tablet"
45 if ! echo "$valid_subtypes" | grep -qw "$subtype"; then
46 log::error "Invalid subtype: ${subtype} (valid: desktop, laptop, phone, tablet)"
47 return 1
48 fi
49 effective_type="guest-${subtype}"
50 fi
51
52 # Build full client name
53 local full_name="${type}-${name}"
54
55 # Validate
56 cmd::add::validate "$name" "$type" "$ip" "$tunnel" || return 1
57
58 # Resolve tunnel mode — flag > device default
59 if [[ -z "$tunnel" ]]; then
60 tunnel=$(config::default_tunnel_for "$type")
61 fi
62
63 # Determine rule — explicit flag > type default
64 if [[ -z "$rule" ]]; then
65 if config::is_guest_type "$type"; then
66 rule="guest"
67 else
68 rule="user"
69 fi
70 fi
71
72 # Validate rule if specified
73 if ! rule::exists "$rule"; then
74 log::error "Rule not found: ${rule}"
75 return 1
76 fi
77
78 local allowed_ips
79 allowed_ips=$(config::allowed_ips_for "$effective_type" "$tunnel") || return 1
80
81 log::section "Adding client: ${full_name}"
82
83 # Auto-assign IP if not provided
84 if [[ -z "$ip" ]]; then
85 ip=$(ip::next_for_type "$effective_type") || return 1
86 fi
87
88 log::wg_add "Name: ${full_name}"
89 log::wg_add "Type: ${type}"
90 log::wg_add "IP: ${ip}"
91 log::wg_add "Tunnel: ${tunnel} (${allowed_ips})"
92
93 # Generate keys
94 keys::generate_pair "$full_name" || return 1
95
96 # Create client config
97 peers::create_client_config "$full_name" "$effective_type" "$ip" "$allowed_ips" || return 1
98
99 # Store subtype in meta
100 if [[ -n "$subtype" ]]; then
101 peers::set_meta "$full_name" "subtype" "$subtype"
102 fi
103
104 # Add peer to server config
105 local public_key
106 public_key=$(keys::public "$full_name") || return 1
107 peers::add_to_server "$full_name" "$public_key" "$ip" || return 1
108
109 log::wg_add "Rule: ${rule:-none}"
110
111 # Apply presets
112 for preset in "${presets[@]}"; do
113 fw::apply_preset "$preset" "${ip}" || return 1
114 done
115
116 # Apply rule
117 if [[ -n "$rule" ]]; then
118 rule::apply "$rule" "$ip" || return 1
119 fi
120
121 # Reload WireGuard
122 peers::reload || return 1
123
124 log::wg_success "Client added successfully: ${full_name} (${ip}) [${tunnel} tunnel]"
125
126 # Show QR for mobile by default, config for desktop/laptop
127 local display_type="${subtype:-$type}"
128
129 if cmd::add::is_mobile "$display_type"; then
130 keys::qr "$full_name"
131 else
132 log::section "Client Config"
133 cat "$(ctx::clients)/${full_name}.conf"
134 fi
135}