Skip to content

Commit c3b17c2

Browse files
committed
add -gpk, -spk and -apk functionality
1 parent 8a66875 commit c3b17c2

1 file changed

Lines changed: 199 additions & 1 deletion

File tree

node_cli.py

Lines changed: 199 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
from urllib3.exceptions import InsecureRequestWarning
3232
import uvicorn
3333
from Framework.Built_In_Automation.Web.Selenium.utils import ChromeExtensionDownloader
34+
from cryptography.hazmat.primitives.asymmetric import rsa
35+
from cryptography.hazmat.primitives import serialization
36+
37+
from settings import ZEUZ_NODE_PRIVATE_RSA_KEYS_DIR
3438

3539

3640
print(
@@ -645,7 +649,6 @@ def update_machine(dependency, should_print=True):
645649
if data["registered"]:
646650
if should_print:
647651
rich_print = console.print
648-
# rich_print(":green_circle: Zeuz Node is online: ", end="")
649652
rich_print(":green_circle: " + data["name"], style="bold cyan", end="")
650653
print(" is online\n")
651654
CommonUtil.ExecLog(
@@ -728,6 +731,151 @@ def get_folder_creation_time(folder_path):
728731
return dt.fromtimestamp(creation_time).date()
729732

730733

734+
def generate_rsa_key():
735+
"""Generate a new RSA private key and save it to the rsa_private_keys folder."""
736+
console = Console()
737+
738+
key_folder = ZEUZ_NODE_PRIVATE_RSA_KEYS_DIR
739+
key_folder.mkdir(parents=True, exist_ok=True)
740+
741+
private_key = rsa.generate_private_key(
742+
public_exponent=65537,
743+
key_size=2048,
744+
)
745+
746+
timestamp = dt.now().strftime("%Y%m%d_%H%M%S")
747+
key_filename = f"private_key_{timestamp}.pem"
748+
key_path = key_folder / key_filename
749+
750+
# Save private key
751+
with open(key_path, 'wb') as f:
752+
f.write(private_key.private_bytes(
753+
encoding=serialization.Encoding.PEM,
754+
format=serialization.PrivateFormat.PKCS8,
755+
encryption_algorithm=serialization.NoEncryption()
756+
))
757+
758+
# Generate public key
759+
public_key = private_key.public_key()
760+
public_key_pem = public_key.public_bytes(
761+
encoding=serialization.Encoding.PEM,
762+
format=serialization.PublicFormat.SubjectPublicKeyInfo
763+
).decode('utf-8')
764+
765+
console.print(f"\n[green]✓[/green] RSA private key generated successfully!")
766+
console.print(f"[cyan]Location:[/cyan] {key_path}")
767+
console.print(f"\n[cyan]Public Key:[/cyan]")
768+
console.print(public_key_pem)
769+
770+
return key_path
771+
772+
773+
def add_existing_rsa_key(key_content: str):
774+
"""Copy an existing RSA private key to the rsa_private_keys folder."""
775+
console = Console()
776+
777+
key_folder = ZEUZ_NODE_PRIVATE_RSA_KEYS_DIR
778+
key_folder.mkdir(parents=True, exist_ok=True)
779+
780+
try:
781+
private_key = serialization.load_pem_private_key(
782+
key_content.encode('utf-8'),
783+
password=None,
784+
)
785+
except Exception as e:
786+
console.print(f"[red]Error:[/red] Invalid PEM private key. {e}")
787+
return False
788+
789+
new_public_key = private_key.public_key()
790+
new_public_key_pem = new_public_key.public_bytes(
791+
encoding=serialization.Encoding.PEM,
792+
format=serialization.PublicFormat.SubjectPublicKeyInfo
793+
).decode('utf-8')
794+
795+
pem_files = list(key_folder.glob("*.pem"))
796+
for pem_file in pem_files:
797+
try:
798+
with open(pem_file, 'rb') as f:
799+
existing_private_key = serialization.load_pem_private_key(f.read(), password=None)
800+
existing_public_key = existing_private_key.public_key()
801+
existing_public_key_pem = existing_public_key.public_bytes(
802+
encoding=serialization.Encoding.PEM,
803+
format=serialization.PublicFormat.SubjectPublicKeyInfo
804+
).decode('utf-8')
805+
if existing_public_key_pem == new_public_key_pem:
806+
console.print(f"[yellow]Warning:[/yellow] This private key already exists as {pem_file.name}. Not adding duplicate.")
807+
return False
808+
except Exception as e:
809+
console.print(f"[red]Error checking existing key {pem_file.name}:[/red] {e}")
810+
continue
811+
812+
# Copy the key with a timestamp
813+
timestamp = dt.now().strftime("%Y%m%d_%H%M%S")
814+
new_filename = f"imported_key_{timestamp}.pem"
815+
new_key_path = key_folder / new_filename
816+
817+
with open(new_key_path, 'wb') as f:
818+
f.write(private_key.private_bytes(
819+
encoding=serialization.Encoding.PEM,
820+
format=serialization.PrivateFormat.PKCS8,
821+
encryption_algorithm=serialization.NoEncryption()
822+
))
823+
824+
console.print(f"\n[green]✓[/green] Private key imported successfully!")
825+
console.print(f"[cyan]To:[/cyan] {new_key_path}")
826+
827+
# Show the public key
828+
console.print(f"\n[cyan]Public Key:[/cyan]")
829+
console.print(new_public_key_pem)
830+
831+
return True
832+
833+
834+
def show_existing_rsa_keys():
835+
"""List all existing RSA private keys and show their public keys."""
836+
console = Console()
837+
838+
key_folder = ZEUZ_NODE_PRIVATE_RSA_KEYS_DIR
839+
840+
if not key_folder.exists():
841+
console.print(f"[yellow]![/yellow] No private keys folder found at: {key_folder}")
842+
console.print("[yellow]![/yellow] Use --generate-key to create a new key.")
843+
return
844+
845+
pem_files = list(key_folder.glob("*.pem"))
846+
847+
if not pem_files:
848+
console.print(f"[yellow]![/yellow] No private keys found in: {key_folder}")
849+
console.print("[yellow]![/yellow] Use --generate-key to create a new key.")
850+
return
851+
852+
console.print(f"\n[cyan]Found {len(pem_files)} private key(s) in:[/cyan] {key_folder}\n")
853+
854+
for idx, pem_file in enumerate(pem_files, 1):
855+
console.print(f"[bold cyan]Key #{idx}:[/bold cyan] {pem_file.name}")
856+
console.print(f"[dim]Path:[/dim] {pem_file}")
857+
858+
try:
859+
with open(pem_file, 'rb') as f:
860+
private_key = serialization.load_pem_private_key(f.read(), password=None)
861+
862+
# Generate and show public key
863+
public_key = private_key.public_key()
864+
public_key_pem = public_key.public_bytes(
865+
encoding=serialization.Encoding.PEM,
866+
format=serialization.PublicFormat.SubjectPublicKeyInfo
867+
).decode('utf-8')
868+
869+
console.print(f"[dim]Public Key:[/dim]")
870+
console.print(public_key_pem)
871+
872+
except Exception as e:
873+
console.print(f"[red]Error loading key:[/red] {e}")
874+
875+
if idx < len(pem_files):
876+
console.print("---")
877+
878+
731879
def command_line_args() -> Path | None:
732880
"""
733881
This function handles command line arguments for configuring and running Zeuz Node.
@@ -762,6 +910,15 @@ def command_line_args() -> Path | None:
762910
Example 9 - Advanced options:
763911
python node_cli.py -spu -sbl -slg
764912
913+
Example 10 - Generate RSA private key:
914+
python node_cli.py -gpk
915+
916+
Example 11 - Add existing RSA private key:
917+
python node_cli.py -apk /path/to/private_key.pem
918+
919+
Example 12 - Show existing RSA keys and their public keys:
920+
python node_cli.py -spk
921+
765922
Use -h or --help to see full documentation of all available arguments.
766923
"""
767924
# try:
@@ -848,6 +1005,27 @@ def command_line_args() -> Path | None:
8481005
metavar="",
8491006
)
8501007

1008+
# RSA key management arguments
1009+
parser_object.add_argument(
1010+
"-gpk",
1011+
"--generate-private-key",
1012+
action="store_true",
1013+
help="Generate a new RSA private key for encrypting secrets",
1014+
)
1015+
parser_object.add_argument(
1016+
"-apk",
1017+
"--add-private-key",
1018+
action="store",
1019+
help="Add an existing RSA private key (provide content of the .pem file)",
1020+
metavar="",
1021+
)
1022+
parser_object.add_argument(
1023+
"-spk",
1024+
"--show-private-keys",
1025+
action="store_true",
1026+
help="Show all existing RSA private keys and their public keys",
1027+
)
1028+
8511029
all_arguments = parser_object.parse_args()
8521030

8531031
server = all_arguments.server
@@ -864,6 +1042,26 @@ def command_line_args() -> Path | None:
8641042
chrome_fetch = all_arguments.chrome_fetch
8651043
chrome_cleanup = all_arguments.chrome_cleanup
8661044

1045+
# RSA key management options
1046+
generate_key = all_arguments.generate_private_key
1047+
add_key = all_arguments.add_private_key
1048+
show_keys = all_arguments.show_private_keys
1049+
1050+
# Handle RSA key management commands
1051+
if generate_key:
1052+
generate_rsa_key()
1053+
sys.exit(0)
1054+
1055+
if add_key:
1056+
if add_existing_rsa_key(add_key):
1057+
sys.exit(0)
1058+
else:
1059+
sys.exit(1)
1060+
1061+
if show_keys:
1062+
show_existing_rsa_keys()
1063+
sys.exit(0)
1064+
8671065
# Update chrome extension download settings if specified
8681066
if chrome_fetch is not None:
8691067
os.environ["CHROME_DAYS_BEFORE_FETCH"] = str(chrome_fetch)

0 commit comments

Comments
 (0)