feat(nodes): Add optional port parameter for node management

This commit is contained in:
ReturnFI
2025-10-16 19:22:49 +00:00
parent 3b58a0273f
commit db82da6e62
3 changed files with 24 additions and 10 deletions

View File

@ -331,12 +331,13 @@ def node():
@node.command('add') @node.command('add')
@click.option('--name', required=True, type=str, help='A unique name for the node (e.g., "Node-DE").') @click.option('--name', required=True, type=str, help='A unique name for the node (e.g., "Node-DE").')
@click.option('--ip', required=True, type=str, help='The public IP address of the node.') @click.option('--ip', required=True, type=str, help='The public IP address of the node.')
@click.option('--sni', required=False, type=str, help='Optional: The Server Name Indication (e.g., yourdomain.com).') @click.option('--port', required=False, type=int, help='Optional: The port of the node.')
@click.option('--sni', required=False, type=str, help='Optional: The Server Name Indication.')
@click.option('--pinSHA256', required=False, type=str, help='Optional: The public key SHA256 pin.') @click.option('--pinSHA256', required=False, type=str, help='Optional: The public key SHA256 pin.')
def add_node(name, ip, sni, pinsha256): def add_node(name, ip, port, sni, pinsha256):
"""Add a new external node.""" """Add a new external node."""
try: try:
output = cli_api.add_node(name, ip, sni, pinSHA256=pinsha256) output = cli_api.add_node(name, ip, sni, pinSHA256=pinsha256, port=port)
click.echo(output.strip()) click.echo(output.strip())
except Exception as e: except Exception as e:
click.echo(f'{e}', err=True) click.echo(f'{e}', err=True)

View File

@ -464,11 +464,13 @@ def edit_ip_address(ipv4: str, ipv6: str):
if ipv6: if ipv6:
run_cmd(['python3', Command.IP_ADD.value, 'edit', '-6', ipv6]) run_cmd(['python3', Command.IP_ADD.value, 'edit', '-6', ipv6])
def add_node(name: str, ip: str, sni: Optional[str] = None, pinSHA256: Optional[str] = None): def add_node(name: str, ip: str, sni: Optional[str] = None, pinSHA256: Optional[str] = None, port: Optional[int] = None):
""" """
Adds a new external node. Adds a new external node.
""" """
command = ['python3', Command.NODE_MANAGER.value, 'add', '--name', name, '--ip', ip] command = ['python3', Command.NODE_MANAGER.value, 'add', '--name', name, '--ip', ip]
if port:
command.extend(['--port', str(port)])
if sni: if sni:
command.extend(['--sni', sni]) command.extend(['--sni', sni])
if pinSHA256: if pinSHA256:

View File

@ -49,6 +49,9 @@ def is_valid_sha256_pin(value: str) -> bool:
pin_regex = re.compile(r'^([0-9A-F]{2}:){31}[0-9A-F]{2}$') pin_regex = re.compile(r'^([0-9A-F]{2}:){31}[0-9A-F]{2}$')
return re.match(pin_regex, value) is not None return re.match(pin_regex, value) is not None
def is_valid_port(port: int) -> bool:
return 1 <= port <= 65535
def read_nodes(): def read_nodes():
if not NODES_JSON_PATH.exists(): if not NODES_JSON_PATH.exists():
return [] return []
@ -69,19 +72,23 @@ def write_nodes(nodes):
except (IOError, OSError) as e: except (IOError, OSError) as e:
sys.exit(f"Error writing to {NODES_JSON_PATH}: {e}") sys.exit(f"Error writing to {NODES_JSON_PATH}: {e}")
def add_node(name: str, ip: str, sni: str | None = None, pinSHA256: str | None = None): def add_node(name: str, ip: str, sni: str | None = None, pinSHA256: str | None = None, port: int | None = None):
if not is_valid_ip_or_domain(ip): if not is_valid_ip_or_domain(ip):
print(f"Error: '{ip}' is not a valid IP address or domain name.", file=sys.stderr) print(f"Error: '{ip}' is not a valid IP address or domain name.", file=sys.stderr)
sys.exit(1) sys.exit(1)
if sni and not is_valid_sni(sni): if sni and not is_valid_sni(sni):
print(f"Error: '{sni}' is not a valid domain name for SNI. Do not include http/https and ensure it's not an IP.", file=sys.stderr) print(f"Error: '{sni}' is not a valid domain name for SNI.", file=sys.stderr)
sys.exit(1) sys.exit(1)
if pinSHA256 and not is_valid_sha256_pin(pinSHA256): if pinSHA256 and not is_valid_sha256_pin(pinSHA256):
print(f"Error: '{pinSHA256}' is not a valid SHA256 pin format.", file=sys.stderr) print(f"Error: '{pinSHA256}' is not a valid SHA256 pin format.", file=sys.stderr)
sys.exit(1) sys.exit(1)
if port and not is_valid_port(port):
print(f"Error: Port '{port}' must be between 1 and 65535.", file=sys.stderr)
sys.exit(1)
nodes = read_nodes() nodes = read_nodes()
if any(node['name'] == name for node in nodes): if any(node['name'] == name for node in nodes):
print(f"Error: A node with the name '{name}' already exists.", file=sys.stderr) print(f"Error: A node with the name '{name}' already exists.", file=sys.stderr)
@ -95,6 +102,8 @@ def add_node(name: str, ip: str, sni: str | None = None, pinSHA256: str | None =
new_node["sni"] = sni.strip() new_node["sni"] = sni.strip()
if pinSHA256: if pinSHA256:
new_node["pinSHA256"] = pinSHA256.strip().upper() new_node["pinSHA256"] = pinSHA256.strip().upper()
if port:
new_node["port"] = port
nodes.append(new_node) nodes.append(new_node)
write_nodes(nodes) write_nodes(nodes)
@ -118,14 +127,15 @@ def list_nodes():
print("No nodes configured.") print("No nodes configured.")
return return
print(f"{'Name':<20} {'IP / Domain':<25} {'SNI':<25} {'Pin SHA256'}") print(f"{'Name':<20} {'IP / Domain':<25} {'Port':<10} {'SNI':<25} {'Pin SHA256'}")
print(f"{'-'*20} {'-'*25} {'-'*25} {'-'*30}") print(f"{'-'*20} {'-'*25} {'-'*10} {'-'*25} {'-'*30}")
for node in sorted(nodes, key=lambda x: x['name']): for node in sorted(nodes, key=lambda x: x['name']):
name = node['name'] name = node['name']
ip = node['ip'] ip = node['ip']
port = node.get('port', 'N/A')
sni = node.get('sni', 'N/A') sni = node.get('sni', 'N/A')
pin = node.get('pinSHA256', 'N/A') pin = node.get('pinSHA256', 'N/A')
print(f"{name:<20} {ip:<25} {sni:<25} {pin}") print(f"{name:<20} {ip:<25} {str(port):<10} {sni:<25} {pin}")
def generate_cert(): def generate_cert():
try: try:
@ -185,6 +195,7 @@ def main():
add_parser = subparsers.add_parser('add', help='Add a new node.') add_parser = subparsers.add_parser('add', help='Add a new node.')
add_parser.add_argument('--name', type=str, required=True, help='The unique name of the node.') add_parser.add_argument('--name', type=str, required=True, help='The unique name of the node.')
add_parser.add_argument('--ip', type=str, required=True, help='The IP address or domain of the node.') add_parser.add_argument('--ip', type=str, required=True, help='The IP address or domain of the node.')
add_parser.add_argument('--port', type=int, help='Optional: The port of the node.')
add_parser.add_argument('--sni', type=str, help='Optional: The Server Name Indication (e.g., yourdomain.com).') add_parser.add_argument('--sni', type=str, help='Optional: The Server Name Indication (e.g., yourdomain.com).')
add_parser.add_argument('--pinSHA256', type=str, help='Optional: The public key SHA256 pin.') add_parser.add_argument('--pinSHA256', type=str, help='Optional: The public key SHA256 pin.')
@ -198,7 +209,7 @@ def main():
args = parser.parse_args() args = parser.parse_args()
if args.command == 'add': if args.command == 'add':
add_node(args.name, args.ip, args.sni, args.pinSHA256) add_node(args.name, args.ip, args.sni, args.pinSHA256, args.port)
elif args.command == 'delete': elif args.command == 'delete':
delete_node(args.name) delete_node(args.name)
elif args.command == 'list': elif args.command == 'list':