raijin-server 0.3.0__py3-none-any.whl → 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of raijin-server might be problematic. Click here for more details.

raijin_server/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """Pacote principal do CLI Raijin Server."""
2
2
 
3
- __version__ = "0.3.0"
3
+ __version__ = "0.3.2"
4
4
 
5
5
  __all__ = ["__version__"]
@@ -103,22 +103,58 @@ def _list_existing_clients() -> List[dict]:
103
103
  content = WG0_CONF.read_text()
104
104
  clients = []
105
105
 
106
- # Parse peers
107
- current_peer = {}
108
- for line in content.split("\n"):
109
- line = line.strip()
106
+ # Parse peers - suporta múltiplos formatos de comentário
107
+ lines = content.split("\n")
108
+ i = 0
109
+
110
+ while i < len(lines):
111
+ line = lines[i].strip()
112
+
113
+ # Detecta início de um bloco [Peer]
114
+ if line == "[Peer]":
115
+ peer_name = None
116
+ public_key = None
117
+ allowed_ips = None
118
+
119
+ # Verifica linha anterior para comentário com nome
120
+ if i > 0:
121
+ prev_line = lines[i - 1].strip()
122
+ # Formato: "# cliente_nome" ou "# Cliente: nome"
123
+ if prev_line.startswith("#"):
124
+ comment = prev_line[1:].strip()
125
+ if comment.lower().startswith("cliente:"):
126
+ peer_name = comment.split(":", 1)[1].strip()
127
+ else:
128
+ # Nome direto após # (formato do módulo vpn)
129
+ peer_name = comment
130
+
131
+ # Lê configurações do peer
132
+ i += 1
133
+ while i < len(lines):
134
+ peer_line = lines[i].strip()
135
+ if peer_line.startswith("[") or (peer_line.startswith("#") and i + 1 < len(lines) and lines[i + 1].strip() == "[Peer]"):
136
+ break
137
+
138
+ if peer_line.startswith("PublicKey"):
139
+ public_key = peer_line.split("=", 1)[1].strip()
140
+ elif peer_line.startswith("AllowedIPs"):
141
+ allowed_ips = peer_line.split("=", 1)[1].strip()
142
+ # Comentário inline com nome do cliente
143
+ elif peer_line.startswith("#") and not peer_name:
144
+ peer_name = peer_line[1:].strip()
145
+
146
+ i += 1
147
+
148
+ # Adiciona peer se tiver pelo menos chave pública
149
+ if public_key:
150
+ clients.append({
151
+ "name": peer_name or f"cliente_{len(clients) + 1}",
152
+ "public_key": public_key,
153
+ "ip": allowed_ips or "N/A",
154
+ })
155
+ continue
110
156
 
111
- if line.startswith("# Cliente:"):
112
- if current_peer:
113
- clients.append(current_peer)
114
- current_peer = {"name": line.split(":", 1)[1].strip()}
115
- elif line.startswith("PublicKey =") and current_peer:
116
- current_peer["public_key"] = line.split("=")[1].strip()
117
- elif line.startswith("AllowedIPs =") and current_peer:
118
- current_peer["ip"] = line.split("=")[1].strip()
119
-
120
- if current_peer:
121
- clients.append(current_peer)
157
+ i += 1
122
158
 
123
159
  return clients
124
160
 
@@ -148,62 +184,87 @@ def _add_peer_to_server(name: str, public_key: str, client_ip: str, ctx: Executi
148
184
  """Adiciona peer ao arquivo de configuração do servidor."""
149
185
  content = WG0_CONF.read_text()
150
186
 
187
+ # Remove linhas em branco extras no final
188
+ content = content.rstrip() + "\n"
189
+
190
+ # Formato compatível com o módulo vpn original
151
191
  peer_block = f"""
152
- # Cliente: {name}
192
+ # {name}
153
193
  [Peer]
154
194
  PublicKey = {public_key}
155
195
  AllowedIPs = {client_ip}
156
196
  """
157
197
 
158
198
  # Adiciona peer ao final
159
- content += "\n" + peer_block
199
+ content += peer_block
160
200
 
161
201
  write_file(WG0_CONF, content, ctx)
162
202
 
163
- # Recarrega configuração
203
+ # Recarrega configuração via wg syncconf (mais rápido) ou restart
164
204
  typer.echo("Recarregando WireGuard...")
165
- run_cmd(["systemctl", "restart", "wg-quick@wg0"], ctx, check=False)
205
+ # Tenta wg syncconf primeiro (não derruba conexões existentes)
206
+ result = run_cmd(
207
+ ["bash", "-c", f"wg syncconf wg0 <(wg-quick strip wg0)"],
208
+ ctx,
209
+ check=False
210
+ )
211
+ if result.returncode != 0:
212
+ # Fallback para restart
213
+ run_cmd(["systemctl", "restart", "wg-quick@wg0"], ctx, check=False)
166
214
 
167
215
 
168
216
  def _remove_peer_from_server(public_key: str, ctx: ExecutionContext) -> None:
169
217
  """Remove peer do arquivo de configuração do servidor."""
170
218
  content = WG0_CONF.read_text()
171
219
 
172
- # Remove bloco do peer
220
+ # Remove bloco do peer - suporta múltiplos formatos
173
221
  lines = content.split("\n")
174
222
  new_lines = []
175
223
  skip_until_next_section = False
176
224
 
177
- for line in lines:
225
+ for i, line in enumerate(lines):
178
226
  if f"PublicKey = {public_key}" in line:
179
227
  skip_until_next_section = True
180
- # Remove também o comentário anterior
181
- if new_lines and new_lines[-1].startswith("# Cliente:"):
182
- new_lines.pop()
183
- if new_lines and new_lines[-1].strip() == "":
184
- new_lines.pop()
185
- if new_lines and new_lines[-1].strip() == "[Peer]":
228
+ # Remove também o comentário anterior e [Peer]
229
+ while new_lines and (
230
+ new_lines[-1].startswith("#") or
231
+ new_lines[-1].strip() == "" or
232
+ new_lines[-1].strip() == "[Peer]"
233
+ ):
186
234
  new_lines.pop()
187
235
  continue
188
236
 
189
237
  if skip_until_next_section:
190
- if line.startswith("[") or line.startswith("# Cliente:"):
238
+ # Próximo peer ou seção
239
+ stripped = line.strip()
240
+ if stripped.startswith("[") or (stripped.startswith("#") and i + 1 < len(lines) and lines[i + 1].strip() == "[Peer]"):
191
241
  skip_until_next_section = False
192
242
  else:
193
243
  continue
194
244
 
195
245
  new_lines.append(line)
196
246
 
197
- write_file(WG0_CONF, "\n".join(new_lines), ctx)
247
+ # Remove linhas em branco extras no final
248
+ while new_lines and new_lines[-1].strip() == "":
249
+ new_lines.pop()
250
+
251
+ write_file(WG0_CONF, "\n".join(new_lines) + "\n", ctx)
198
252
 
199
253
  # Recarrega configuração
200
254
  typer.echo("Recarregando WireGuard...")
201
- run_cmd(["systemctl", "restart", "wg-quick@wg0"], ctx, check=False)
255
+ result = run_cmd(
256
+ ["bash", "-c", f"wg syncconf wg0 <(wg-quick strip wg0)"],
257
+ ctx,
258
+ check=False
259
+ )
260
+ if result.returncode != 0:
261
+ run_cmd(["systemctl", "restart", "wg-quick@wg0"], ctx, check=False)
202
262
 
203
263
 
204
264
  def _create_client_config(
205
265
  name: str,
206
266
  private_key: str,
267
+ public_key: str,
207
268
  client_ip: str,
208
269
  server_config: dict,
209
270
  ) -> str:
@@ -218,8 +279,10 @@ def _create_client_config(
218
279
  if not endpoint:
219
280
  endpoint = typer.prompt("Endpoint público do servidor (IP ou domínio)")
220
281
 
221
- config = f"""[Interface]
222
- # Cliente: {name}
282
+ # Inclui chave pública do cliente como comentário para referência rápida
283
+ config = f"""# Cliente: {name}
284
+ # PublicKey: {public_key}
285
+ [Interface]
223
286
  PrivateKey = {private_key}
224
287
  Address = {client_ip}
225
288
  DNS = {dns}
@@ -272,7 +335,7 @@ def add_client(ctx: ExecutionContext) -> None:
272
335
  CLIENTS_DIR.mkdir(parents=True, exist_ok=True)
273
336
 
274
337
  # Cria configuração do cliente
275
- client_config = _create_client_config(name, private_key, client_ip, server_config)
338
+ client_config = _create_client_config(name, private_key, public_key, client_ip, server_config)
276
339
 
277
340
  client_file = CLIENTS_DIR / f"{name}.conf"
278
341
  write_file(client_file, client_config, ctx)
@@ -387,6 +450,8 @@ def show_client_config(ctx: ExecutionContext) -> None:
387
450
 
388
451
  if not client_file.exists():
389
452
  typer.secho(f"Arquivo de configuração não encontrado: {client_file}", fg=typer.colors.RED)
453
+ typer.echo("\nDica: O cliente pode ter sido criado pelo módulo 'vpn' (inicial).")
454
+ typer.echo(f"Verifique se existe: {CLIENTS_DIR}")
390
455
  raise typer.Exit(1)
391
456
 
392
457
  typer.echo(f"\n{'='*60}")
@@ -396,11 +461,37 @@ def show_client_config(ctx: ExecutionContext) -> None:
396
461
 
397
462
  typer.echo(client_file.read_text())
398
463
 
464
+ # Detecta hostname/IP do servidor
465
+ import socket
466
+ hostname = socket.gethostname()
467
+
468
+ typer.echo(f"\n{'='*60}")
469
+ typer.secho("COMO COPIAR PARA WINDOWS/MAC/LINUX:", fg=typer.colors.CYAN, bold=True)
470
+ typer.echo(f"{'='*60}")
471
+
472
+ typer.echo("\n📋 Opção 1 - SCP (requer SSH configurado):")
473
+ typer.echo(f" scp usuario@{hostname}:{client_file} .")
474
+ typer.echo(f" # ou com IP: scp usuario@SEU_IP:{client_file} .")
475
+
476
+ typer.echo("\n📋 Opção 2 - Copiar conteúdo manualmente:")
477
+ typer.echo(" 1. Copie o texto acima (entre as linhas de '=')")
478
+ typer.echo(f" 2. No Windows, crie arquivo: {name}.conf")
479
+ typer.echo(" 3. Cole o conteúdo e salve")
480
+
481
+ typer.echo("\n📋 Opção 3 - SFTP (FileZilla, WinSCP):")
482
+ typer.echo(f" Conecte no servidor e baixe: {client_file}")
483
+
484
+ typer.echo("\n📱 Para celular (QR Code):")
485
+ typer.echo(f" qrencode -t ansiutf8 < {client_file}")
486
+
399
487
  typer.echo(f"\n{'='*60}")
400
- typer.echo("\nPara copiar:")
401
- typer.echo(f" scp root@servidor:{client_file} .")
402
- typer.echo("\nPara QR code (mobile):")
403
- typer.echo(f" qrencode -t ansiutf8 {client_file}")
488
+ typer.secho("NO WINDOWS 11:", fg=typer.colors.GREEN, bold=True)
489
+ typer.echo(f"{'='*60}")
490
+ typer.echo(" 1. Baixe WireGuard: https://www.wireguard.com/install/")
491
+ typer.echo(" 2. Abra WireGuard → 'Import tunnel(s) from file...'")
492
+ typer.echo(f" 3. Selecione o arquivo {name}.conf")
493
+ typer.echo(" 4. Clique 'Activate' para conectar")
494
+ typer.echo("")
404
495
 
405
496
 
406
497
  def run(ctx: ExecutionContext) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: raijin-server
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: CLI para automacao de setup e hardening de servidores Ubuntu Server.
5
5
  Home-page: https://example.com/raijin-server
6
6
  Author: Equipe Raijin
@@ -269,6 +269,7 @@ kubectl port-forward svc/grafana -n observability 3000:80
269
269
  | [ARCHITECTURE.md](ARCHITECTURE.md) | Arquitetura técnica do ambiente |
270
270
  | [SECURITY.md](SECURITY.md) | Políticas de segurança |
271
271
  | [AUDIT.md](AUDIT.md) | Relatório de auditoria |
272
+ | [docs/VERSIONING.md](docs/VERSIONING.md) | Versionamento e tags |
272
273
  | [docs/INFRASTRUCTURE_GUIDE.md](docs/INFRASTRUCTURE_GUIDE.md) | Guia completo de infraestrutura |
273
274
  | [docs/VPN_REMOTE_ACCESS.md](docs/VPN_REMOTE_ACCESS.md) | Configuração de VPN |
274
275
  | [docs/INTERNAL_DNS.md](docs/INTERNAL_DNS.md) | DNS interno para domínios privados |
@@ -1,4 +1,4 @@
1
- raijin_server/__init__.py,sha256=MvrRbjHr0fpwAuK-h3JmhGK1xckNu_HpfUU0CsifboQ,94
1
+ raijin_server/__init__.py,sha256=A06gLxft508OGSQ5sPqJhuqoAoEB0hkD0koIF-UP0SQ,94
2
2
  raijin_server/cli.py,sha256=rqkAQCU5imi52YJCIeEuZqWo8bWYkVErOQh3JpKIDok,38149
3
3
  raijin_server/config.py,sha256=QNiEVvrbW56XgvNn5-h3bkJm46Xc8mjNqPbvixXD8N0,4829
4
4
  raijin_server/healthchecks.py,sha256=lzXdFw6S0hOYbUKbqksh4phb04lXgXdTspP1Dsz4dx8,15401
@@ -34,15 +34,15 @@ raijin_server/modules/ssh_hardening.py,sha256=Zd0dlylUBr01SkrI1CS05-0DB9xIto5rWH
34
34
  raijin_server/modules/traefik.py,sha256=omziywss4o-8t64Kj-upLqbXdFYm2JwqOoOukDUmqxY,5008
35
35
  raijin_server/modules/velero.py,sha256=yDtqd6yUu0L5wzLCjYXqvvxB_RyaAoZtntb6HoHVAOo,5642
36
36
  raijin_server/modules/vpn.py,sha256=hF-0vA17VKTxhQLDBSEeqI5aPQpiaaj4IpUf9l6lr64,8297
37
- raijin_server/modules/vpn_client.py,sha256=sea5PtJB3Q612cVvW4Pz8_fEN7Zu0eNf34D2uEfHnkw,13463
37
+ raijin_server/modules/vpn_client.py,sha256=6P5mYLTgQr5fqjTftY6jW3p_iRXy5YVNxfkLfP0mujs,17228
38
38
  raijin_server/scripts/__init__.py,sha256=deduGfHf8BMVWred4ux5LfBDT2NJ5XYeJAt2sDEU4qs,53
39
39
  raijin_server/scripts/checklist.sh,sha256=j6E0Kmk1EfjLvKK1VpCqzXJAXI_7Bm67LK4ndyCxWh0,1842
40
40
  raijin_server/scripts/install.sh,sha256=Y1ickbQ4siQ0NIPs6UgrqUr8WWy7U0LHmaTQbEgavoI,3949
41
41
  raijin_server/scripts/log_size_metric.sh,sha256=Iv4SsX8AuCYRou-klYn32mX41xB6j0xJGLBO6riw4rU,1208
42
42
  raijin_server/scripts/pre-deploy-check.sh,sha256=XqMo7IMIpwUHF17YEmU0-cVmTDMoCGMBFnmS39FidI4,4912
43
- raijin_server-0.3.0.dist-info/licenses/LICENSE,sha256=kJsMCjOiRZE0AQNtxWqBa32z9kMAaF4EUxyHj3hKaJo,1105
44
- raijin_server-0.3.0.dist-info/METADATA,sha256=nyqyXiUg4iGNViT9GKvXT1zelFsKUya3HO3QBBAjeVM,8761
45
- raijin_server-0.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
46
- raijin_server-0.3.0.dist-info/entry_points.txt,sha256=3ZvxDX4pvcjkIRsXAJ69wIfVmKa78LKo-C3QhqN2KVM,56
47
- raijin_server-0.3.0.dist-info/top_level.txt,sha256=Yz1xneCRtsZOzbPIcTAcrSxd-1p80pohMXYAZ74dpok,14
48
- raijin_server-0.3.0.dist-info/RECORD,,
43
+ raijin_server-0.3.2.dist-info/licenses/LICENSE,sha256=kJsMCjOiRZE0AQNtxWqBa32z9kMAaF4EUxyHj3hKaJo,1105
44
+ raijin_server-0.3.2.dist-info/METADATA,sha256=0YsPOlPDXXMTDqNNWcYfcfiwn-C8mw0spAcAGo-XuTU,8829
45
+ raijin_server-0.3.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
46
+ raijin_server-0.3.2.dist-info/entry_points.txt,sha256=3ZvxDX4pvcjkIRsXAJ69wIfVmKa78LKo-C3QhqN2KVM,56
47
+ raijin_server-0.3.2.dist-info/top_level.txt,sha256=Yz1xneCRtsZOzbPIcTAcrSxd-1p80pohMXYAZ74dpok,14
48
+ raijin_server-0.3.2.dist-info/RECORD,,