broadfield-dev commited on
Commit
ac072a2
Β·
verified Β·
1 Parent(s): b04a886

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -30
app.py CHANGED
@@ -1,26 +1,39 @@
1
  import gradio as gr
2
- import json
3
- import os
4
- import io
5
  import base64
6
- import struct
 
7
  import logging
 
8
  import requests
9
- from PIL import Image, ImageDraw, ImageFont
 
10
  import numpy as np
11
- from cryptography.hazmat.primitives.ciphers.aead import AESGCM
12
- from cryptography.hazmat.primitives import hashes
13
  from cryptography.hazmat.primitives import serialization
14
  from cryptography.hazmat.primitives.asymmetric import rsa, padding
 
 
15
 
16
  # --- Configure Logging ---
17
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
18
  logger = logging.getLogger(__name__)
19
 
20
  # ==============================================================================
21
- # CONFIGURATION
22
  # ==============================================================================
23
- ENDPOINTS_JSON_URL = "https://huggingface.co/spaces/broadfield-dev/KeyLock-Auth-Creator/raw/main/endpoints.json"
 
 
 
 
 
 
 
 
 
 
 
24
 
25
  # ==============================================================================
26
  # LOCAL LOGIC (Key and Image Generation)
@@ -28,8 +41,13 @@ ENDPOINTS_JSON_URL = "https://huggingface.co/spaces/broadfield-dev/KeyLock-Auth-
28
  def generate_rsa_keys():
29
  """Generates a new 2048-bit RSA key pair LOCALLY."""
30
  private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
31
- private_pem = private_key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()).decode('utf-8')
32
- public_pem = private_key.public_key().public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
 
 
 
 
 
33
  return private_pem, public_pem
34
 
35
  def create_encrypted_image(secret_data_str: str, public_key_pem: str) -> Image.Image:
@@ -37,7 +55,20 @@ def create_encrypted_image(secret_data_str: str, public_key_pem: str) -> Image.I
37
  if not secret_data_str.strip(): raise ValueError("Secret data cannot be empty.")
38
  if not public_key_pem.strip(): raise ValueError("Public Key cannot be empty.")
39
 
40
- data_dict = {parts[0].strip(): parts[1].strip().strip("'\"") for line in secret_data_str.splitlines() if (line := line.strip()) and not line.startswith('#') and (parts := (line.split(':', 1) if ':' in line else line.split('=', 1))) and len(parts) == 2}
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  if not data_dict: raise ValueError("No valid key-value pairs found.")
42
 
43
  json_bytes = json.dumps(data_dict).encode('utf-8')
@@ -62,24 +93,22 @@ def create_encrypted_image(secret_data_str: str, public_key_pem: str) -> Image.I
62
  return Image.fromarray(stego_pixels, 'RGB')
63
 
64
  # ==============================================================================
65
- # UI HELPER & REMOTE API CALL LOGIC
66
  # ==============================================================================
67
-
68
- def get_server_list():
69
- """Fetches the list of servers from the public JSON file."""
 
70
  try:
71
- response = requests.get(ENDPOINTS_JSON_URL, timeout=10)
72
  response.raise_for_status()
73
  endpoints = response.json()
74
- # Validate the new structure
75
- for e in endpoints:
76
- if "api_endpoint" not in e: raise ValueError("Configuration Error: Entry is missing the required 'api_endpoint' field.")
77
  endpoint_names = [e['name'] for e in endpoints]
78
- status = f"βœ… Success! Found {len(endpoint_names)} servers."
79
- return gr.Dropdown(choices=endpoint_names, value=endpoint_names[0] if endpoint_names else None, label="Target Server"), status, endpoints
80
  except Exception as e:
81
- status = f"❌ Error fetching configuration: {e}"
82
- return gr.Dropdown(choices=[], value=None, label="Error fetching servers"), status, []
83
 
84
  def create_keylock_wrapper(service_name: str, secret_data: str, available_endpoints: list):
85
  """UI wrapper for creating an image for a selected service."""
@@ -97,14 +126,12 @@ def send_keylock_wrapper(service_name: str, image: Image.Image, available_endpoi
97
  if not service_name: raise gr.Error("Please select a target server.")
98
  if image is None: raise gr.Error("Please upload an image to send.")
99
 
100
- # --- THIS IS THE FIX ---
101
- # Look up the correct, full API endpoint from the configuration. No more guesswork!
102
- api_endpoint = next((e['api_endpoint'] for e in available_endpoints if e['name'] == service_name), None)
103
  if not api_endpoint:
104
  raise gr.Error(f"Configuration Error: Could not find 'api_endpoint' for '{service_name}'.")
105
 
106
  status = f"Connecting to endpoint: {api_endpoint}"
107
- logger.info(status)
108
 
109
  try:
110
  with io.BytesIO() as buffer:
@@ -128,7 +155,7 @@ def send_keylock_wrapper(service_name: str, image: Image.Image, available_endpoi
128
  return None, f"❌ Error calling server API: {e}"
129
 
130
  # ==============================================================================
131
- # GRADIO DASHBOARD INTERFACE
132
  # ==============================================================================
133
  theme = gr.themes.Base(
134
  primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.sky, neutral_hue=gr.themes.colors.slate,
@@ -192,7 +219,6 @@ with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
192
 
193
  def refresh_and_update_all():
194
  dropdown_update, status_update, state_update = get_server_list()
195
- # Update both dropdowns simultaneously from the same source of truth
196
  return dropdown_update, dropdown_update, status_update, state_update
197
 
198
  refresh_button.click(fn=refresh_and_update_all, outputs=[creator_service_dropdown, send_service_dropdown, creator_status, endpoints_state])
 
1
  import gradio as gr
2
+ from gradio_client import Client
3
+ from PIL import Image, ImageDraw, ImageFont
 
4
  import base64
5
+ import io
6
+ import json
7
  import logging
8
+ import os
9
  import requests
10
+ import tempfile
11
+ import struct
12
  import numpy as np
 
 
13
  from cryptography.hazmat.primitives import serialization
14
  from cryptography.hazmat.primitives.asymmetric import rsa, padding
15
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
16
+ from cryptography.hazmat.primitives import hashes
17
 
18
  # --- Configure Logging ---
19
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
20
  logger = logging.getLogger(__name__)
21
 
22
  # ==============================================================================
23
+ # CONFIGURATION: IDs AND URLs OF THE REMOTE SERVICES
24
  # ==============================================================================
25
+ CREATOR_SPACE_ID = "broadfield-dev/KeyLock-Auth-Creator"
26
+ SERVER_SPACE_ID = "broadfield-dev/KeyLock-Auth-Server"
27
+
28
+ # URL to the raw JSON file containing the list of public keys and services.
29
+ CREATOR_ENDPOINTS_JSON_URL = "https://huggingface.co/spaces/broadfield-dev/KeyLock-Auth-Creator/raw/main/endpoints.json"
30
+
31
+ # Construct URLs for linking in documentation
32
+ BASE_HF_URL = "https://huggingface.co/spaces/"
33
+ CREATOR_URL = f"{BASE_HF_URL}{CREATOR_SPACE_ID}"
34
+ SERVER_URL = f"{BASE_HF_URL}{SERVER_SPACE_ID}"
35
+ CREATOR_APP_PY_URL = f"{CREATOR_URL}/blob/main/app.py"
36
+ SERVER_APP_PY_URL = f"{SERVER_URL}/blob/main/app.py"
37
 
38
  # ==============================================================================
39
  # LOCAL LOGIC (Key and Image Generation)
 
41
  def generate_rsa_keys():
42
  """Generates a new 2048-bit RSA key pair LOCALLY."""
43
  private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
44
+ private_pem = private_key.private_bytes(
45
+ encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8,
46
+ encryption_algorithm=serialization.NoEncryption()
47
+ ).decode('utf-8')
48
+ public_pem = private_key.public_key().public_bytes(
49
+ encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo
50
+ ).decode('utf-8')
51
  return private_pem, public_pem
52
 
53
  def create_encrypted_image(secret_data_str: str, public_key_pem: str) -> Image.Image:
 
55
  if not secret_data_str.strip(): raise ValueError("Secret data cannot be empty.")
56
  if not public_key_pem.strip(): raise ValueError("Public Key cannot be empty.")
57
 
58
+ # --- THIS IS THE FIX ---
59
+ # Replaced the failing dictionary comprehension with a standard, readable for loop.
60
+ data_dict = {}
61
+ for line in secret_data_str.splitlines():
62
+ line = line.strip()
63
+ if not line or line.startswith('#'):
64
+ continue
65
+
66
+ parts = line.split(':', 1) if ':' in line else line.split('=', 1)
67
+ if len(parts) == 2:
68
+ key = parts[0].strip()
69
+ value = parts[1].strip().strip("'\"")
70
+ data_dict[key] = value
71
+
72
  if not data_dict: raise ValueError("No valid key-value pairs found.")
73
 
74
  json_bytes = json.dumps(data_dict).encode('utf-8')
 
93
  return Image.fromarray(stego_pixels, 'RGB')
94
 
95
  # ==============================================================================
96
+ # UI HELPER & REMOTE API CALL LOGIC (Your working versions)
97
  # ==============================================================================
98
+ def get_creator_endpoints():
99
+ """Fetches the list of supported endpoints by making an HTTP request to the Creator's JSON file."""
100
+ status = f"Fetching endpoint list from {CREATOR_ENDPOINTS_JSON_URL}..."
101
+ yield gr.Dropdown(choices=[], value=None, label="⏳ Fetching..."), status, [] # Initial state
102
  try:
103
+ response = requests.get(CREATOR_ENDPOINTS_JSON_URL, timeout=10)
104
  response.raise_for_status()
105
  endpoints = response.json()
 
 
 
106
  endpoint_names = [e['name'] for e in endpoints]
107
+ status = f"βœ… Success! Found {len(endpoint_names)} endpoints."
108
+ yield gr.Dropdown(choices=endpoint_names, value=endpoint_names[0] if endpoint_names else None, label="Target Service"), status, endpoints
109
  except Exception as e:
110
+ status = f"❌ Error: Could not fetch configuration. Check the URL and if the 'endpoints.json' file is public. Details: {e}"
111
+ yield gr.Dropdown(choices=[], value=None, label="Error fetching services"), status, []
112
 
113
  def create_keylock_wrapper(service_name: str, secret_data: str, available_endpoints: list):
114
  """UI wrapper for creating an image for a selected service."""
 
126
  if not service_name: raise gr.Error("Please select a target server.")
127
  if image is None: raise gr.Error("Please upload an image to send.")
128
 
129
+ api_endpoint = next((e.get('api_endpoint') for e in available_endpoints if e['name'] == service_name), None)
 
 
130
  if not api_endpoint:
131
  raise gr.Error(f"Configuration Error: Could not find 'api_endpoint' for '{service_name}'.")
132
 
133
  status = f"Connecting to endpoint: {api_endpoint}"
134
+ yield None, status
135
 
136
  try:
137
  with io.BytesIO() as buffer:
 
155
  return None, f"❌ Error calling server API: {e}"
156
 
157
  # ==============================================================================
158
+ # GRADIO DASHBOARD INTERFACE (Your working layout)
159
  # ==============================================================================
160
  theme = gr.themes.Base(
161
  primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.sky, neutral_hue=gr.themes.colors.slate,
 
219
 
220
  def refresh_and_update_all():
221
  dropdown_update, status_update, state_update = get_server_list()
 
222
  return dropdown_update, dropdown_update, status_update, state_update
223
 
224
  refresh_button.click(fn=refresh_and_update_all, outputs=[creator_service_dropdown, send_service_dropdown, creator_status, endpoints_state])