Update app.py
Browse files
app.py
CHANGED
@@ -5,6 +5,7 @@ import base64
|
|
5 |
import io
|
6 |
import json
|
7 |
import logging
|
|
|
8 |
from cryptography.hazmat.primitives import serialization
|
9 |
from cryptography.hazmat.primitives.asymmetric import rsa
|
10 |
|
@@ -18,6 +19,10 @@ logger = logging.getLogger(__name__)
|
|
18 |
CREATOR_SPACE_ID = "broadfield-dev/KeyLock-Auth-Creator"
|
19 |
SERVER_SPACE_ID = "broadfield-dev/KeyLock-Auth-Server"
|
20 |
|
|
|
|
|
|
|
|
|
21 |
# Construct URLs for linking in documentation
|
22 |
BASE_HF_URL = "https://huggingface.co/spaces/"
|
23 |
CREATOR_URL = f"{BASE_HF_URL}{CREATOR_SPACE_ID}"
|
@@ -30,23 +35,23 @@ SERVER_APP_PY_URL = f"{SERVER_URL}/blob/main/app.py"
|
|
30 |
# ==============================================================================
|
31 |
|
32 |
def get_creator_endpoints():
|
33 |
-
"""
|
34 |
-
status = f"Fetching endpoint list from {
|
35 |
-
yield gr.Dropdown(choices=[], value=None, label="β³ Fetching..."), status
|
36 |
try:
|
37 |
-
|
38 |
-
|
39 |
|
40 |
-
endpoints = json
|
41 |
endpoint_names = [e['name'] for e in endpoints]
|
42 |
|
43 |
status = f"β
Success! Found {len(endpoint_names)} endpoints."
|
44 |
# Return the full list to the state, and the updated dropdown
|
45 |
-
yield gr.Dropdown(choices=endpoint_names, value=endpoint_names[0] if endpoint_names else None, label="Target Service"), status
|
46 |
except Exception as e:
|
47 |
-
logger.error(f"Failed to get endpoints from creator: {e}", exc_info=True)
|
48 |
-
status = f"β Error: Could not fetch
|
49 |
-
yield gr.Dropdown(choices=[], value=None, label="Error fetching services"), status
|
50 |
|
51 |
def create_image_via_api(service_name: str, secret_data: str, available_endpoints: list):
|
52 |
"""Calls the Creator Space API to generate an encrypted image for a selected service."""
|
@@ -56,7 +61,6 @@ def create_image_via_api(service_name: str, secret_data: str, available_endpoint
|
|
56 |
status = f"Looking up public key for '{service_name}'..."
|
57 |
yield None, None, status
|
58 |
|
59 |
-
# Find the public key from the list we fetched earlier
|
60 |
public_key = next((e['public_key'] for e in available_endpoints if e['name'] == service_name), None)
|
61 |
if not public_key:
|
62 |
raise gr.Error(f"Could not find public key for '{service_name}' in the fetched configuration.")
|
@@ -120,7 +124,7 @@ theme = gr.themes.Base(
|
|
120 |
neutral_hue=gr.themes.colors.slate,
|
121 |
font=(gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"),
|
122 |
).set(
|
123 |
-
body_background_fill="#F1F5F9",
|
124 |
panel_background_fill="white",
|
125 |
block_background_fill="white",
|
126 |
block_border_width="1px",
|
@@ -130,7 +134,6 @@ theme = gr.themes.Base(
|
|
130 |
)
|
131 |
|
132 |
with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
133 |
-
# This State component will hold the list of dicts fetched from the Creator
|
134 |
endpoints_state = gr.State([])
|
135 |
|
136 |
gr.Markdown("# π KeyLock Operations Dashboard")
|
@@ -153,7 +156,7 @@ with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
|
153 |
with gr.Column(scale=2):
|
154 |
with gr.Row():
|
155 |
creator_service_dropdown = gr.Dropdown(label="Target Service", interactive=True, info="Select the API server you want to encrypt data for.")
|
156 |
-
refresh_button = gr.Button("Refresh List", icon="π", scale=0)
|
157 |
creator_secret_input = gr.Textbox(lines=8, label="Secret Data to Encrypt", placeholder="API_KEY: sk-123...\nUSER: demo-user")
|
158 |
creator_button = gr.Button("Create Auth Image via API", variant="primary", icon="β¨")
|
159 |
with gr.Column(scale=1):
|
@@ -173,49 +176,24 @@ with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
|
173 |
|
174 |
with gr.TabItem("βΉοΈ Service Information", id=3):
|
175 |
gr.Markdown("## Ecosystem Architecture")
|
176 |
-
gr.Markdown(
|
177 |
-
"""
|
178 |
-
This dashboard coordinates separate Hugging Face Spaces to demonstrate a secure, decoupled workflow. Each service has a specific role.
|
179 |
-
"""
|
180 |
-
)
|
181 |
with gr.Row():
|
182 |
with gr.Column():
|
183 |
-
gr.Markdown(f""
|
184 |
-
### π Auth Creator Service
|
185 |
-
- **Space:** [{CREATOR_SPACE_ID}]({CREATOR_URL})
|
186 |
-
- **Role:** Provides a UI and an API to encrypt data into PNG images for various targets. It reads a public configuration file (`endpoints.json`) to know which public keys it can use.
|
187 |
-
- **Source Code:** [app.py]({CREATOR_APP_PY_URL})
|
188 |
-
""")
|
189 |
with gr.Column():
|
190 |
-
gr.Markdown(f""
|
191 |
-
### π‘ Decoder Server
|
192 |
-
- **Space:** [{SERVER_SPACE_ID}]({SERVER_URL})
|
193 |
-
- **Role:** The trusted authority. It holds a **secret private key** and provides a secure API to decrypt images. This is the only component that can read the secret data.
|
194 |
-
- **Source Code:** [app.py]({SERVER_APP_PY_URL})
|
195 |
-
""")
|
196 |
|
197 |
# --- Wire up the component logic ---
|
198 |
gen_keys_button.click(fn=generate_rsa_keys, inputs=None, outputs=[output_private_key, output_public_key])
|
199 |
|
200 |
-
#
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
outputs=[endpoints_state]
|
209 |
-
)
|
210 |
-
refresh_button.click(
|
211 |
-
fn=get_creator_endpoints,
|
212 |
-
inputs=None,
|
213 |
-
outputs=[creator_service_dropdown, creator_status]
|
214 |
-
).then(
|
215 |
-
lambda data: data,
|
216 |
-
js="(data) => data.choices",
|
217 |
-
outputs=[endpoints_state]
|
218 |
-
)
|
219 |
|
220 |
# Logic for the Creator and Client tabs
|
221 |
creator_button.click(fn=create_image_via_api, inputs=[creator_service_dropdown, creator_secret_input, endpoints_state], outputs=[creator_image_output, gr.File(visible=False), creator_status])
|
|
|
5 |
import io
|
6 |
import json
|
7 |
import logging
|
8 |
+
import requests # Use requests to fetch the remote JSON file
|
9 |
from cryptography.hazmat.primitives import serialization
|
10 |
from cryptography.hazmat.primitives.asymmetric import rsa
|
11 |
|
|
|
19 |
CREATOR_SPACE_ID = "broadfield-dev/KeyLock-Auth-Creator"
|
20 |
SERVER_SPACE_ID = "broadfield-dev/KeyLock-Auth-Server"
|
21 |
|
22 |
+
# URL to the raw JSON file containing the list of public keys and services.
|
23 |
+
# This makes the Creator's configuration publicly readable.
|
24 |
+
CREATOR_ENDPOINTS_JSON_URL = "https://huggingface.co/spaces/broadfield-dev/KeyLock-Auth-Creator/raw/main/endpoints.json"
|
25 |
+
|
26 |
# Construct URLs for linking in documentation
|
27 |
BASE_HF_URL = "https://huggingface.co/spaces/"
|
28 |
CREATOR_URL = f"{BASE_HF_URL}{CREATOR_SPACE_ID}"
|
|
|
35 |
# ==============================================================================
|
36 |
|
37 |
def get_creator_endpoints():
|
38 |
+
"""Fetches the list of supported endpoints by making an HTTP request to the Creator's JSON file."""
|
39 |
+
status = f"Fetching endpoint list from {CREATOR_ENDPOINTS_JSON_URL}..."
|
40 |
+
yield gr.Dropdown(choices=[], value=None, label="β³ Fetching..."), status, [] # Initial state
|
41 |
try:
|
42 |
+
response = requests.get(CREATOR_ENDPOINTS_JSON_URL, timeout=10)
|
43 |
+
response.raise_for_status() # Raise an exception for bad status codes
|
44 |
|
45 |
+
endpoints = response.json()
|
46 |
endpoint_names = [e['name'] for e in endpoints]
|
47 |
|
48 |
status = f"β
Success! Found {len(endpoint_names)} endpoints."
|
49 |
# Return the full list to the state, and the updated dropdown
|
50 |
+
yield gr.Dropdown(choices=endpoint_names, value=endpoint_names[0] if endpoint_names else None, label="Target Service"), status, endpoints
|
51 |
except Exception as e:
|
52 |
+
logger.error(f"Failed to get endpoints from creator's JSON file: {e}", exc_info=True)
|
53 |
+
status = f"β Error: Could not fetch configuration. Check the URL and if the 'endpoints.json' file is public. Details: {e}"
|
54 |
+
yield gr.Dropdown(choices=[], value=None, label="Error fetching services"), status, []
|
55 |
|
56 |
def create_image_via_api(service_name: str, secret_data: str, available_endpoints: list):
|
57 |
"""Calls the Creator Space API to generate an encrypted image for a selected service."""
|
|
|
61 |
status = f"Looking up public key for '{service_name}'..."
|
62 |
yield None, None, status
|
63 |
|
|
|
64 |
public_key = next((e['public_key'] for e in available_endpoints if e['name'] == service_name), None)
|
65 |
if not public_key:
|
66 |
raise gr.Error(f"Could not find public key for '{service_name}' in the fetched configuration.")
|
|
|
124 |
neutral_hue=gr.themes.colors.slate,
|
125 |
font=(gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"),
|
126 |
).set(
|
127 |
+
body_background_fill="#F1F5F9",
|
128 |
panel_background_fill="white",
|
129 |
block_background_fill="white",
|
130 |
block_border_width="1px",
|
|
|
134 |
)
|
135 |
|
136 |
with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
|
|
137 |
endpoints_state = gr.State([])
|
138 |
|
139 |
gr.Markdown("# π KeyLock Operations Dashboard")
|
|
|
156 |
with gr.Column(scale=2):
|
157 |
with gr.Row():
|
158 |
creator_service_dropdown = gr.Dropdown(label="Target Service", interactive=True, info="Select the API server you want to encrypt data for.")
|
159 |
+
refresh_button = gr.Button("Refresh List", icon="π", scale=0, size="sm")
|
160 |
creator_secret_input = gr.Textbox(lines=8, label="Secret Data to Encrypt", placeholder="API_KEY: sk-123...\nUSER: demo-user")
|
161 |
creator_button = gr.Button("Create Auth Image via API", variant="primary", icon="β¨")
|
162 |
with gr.Column(scale=1):
|
|
|
176 |
|
177 |
with gr.TabItem("βΉοΈ Service Information", id=3):
|
178 |
gr.Markdown("## Ecosystem Architecture")
|
179 |
+
gr.Markdown("This dashboard coordinates separate Hugging Face Spaces to demonstrate a secure, decoupled workflow. Each service has a specific role.")
|
|
|
|
|
|
|
|
|
180 |
with gr.Row():
|
181 |
with gr.Column():
|
182 |
+
gr.Markdown(f"### π Auth Creator Service\n- **Space:** [{CREATOR_SPACE_ID}]({CREATOR_URL})\n- **Role:** Provides an API to encrypt data for various targets defined in its `endpoints.json` file.\n- **Source Code:** [app.py]({CREATOR_APP_PY_URL})")
|
|
|
|
|
|
|
|
|
|
|
183 |
with gr.Column():
|
184 |
+
gr.Markdown(f"### π‘ Decoder Server\n- **Space:** [{SERVER_SPACE_ID}]({SERVER_URL})\n- **Role:** The trusted authority. It holds a secret private key and provides a secure API to decrypt images.\n- **Source Code:** [app.py]({SERVER_APP_PY_URL})")
|
|
|
|
|
|
|
|
|
|
|
185 |
|
186 |
# --- Wire up the component logic ---
|
187 |
gen_keys_button.click(fn=generate_rsa_keys, inputs=None, outputs=[output_private_key, output_public_key])
|
188 |
|
189 |
+
# Event handler for loading the page or refreshing the endpoint list
|
190 |
+
def refresh_endpoints():
|
191 |
+
# This is a generator function, so we need to iterate to get the last value.
|
192 |
+
*_, last_yield = get_creator_endpoints()
|
193 |
+
return last_yield
|
194 |
+
|
195 |
+
refresh_button.click(fn=refresh_endpoints, outputs=[creator_service_dropdown, creator_status, endpoints_state])
|
196 |
+
demo.load(fn=refresh_endpoints, outputs=[creator_service_dropdown, creator_status, endpoints_state])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
|
198 |
# Logic for the Creator and Client tabs
|
199 |
creator_button.click(fn=create_image_via_api, inputs=[creator_service_dropdown, creator_secret_input, endpoints_state], outputs=[creator_image_output, gr.File(visible=False), creator_status])
|