Update app.py
Browse files
app.py
CHANGED
@@ -28,13 +28,14 @@ CREATOR_APP_PY_URL = f"{CREATOR_URL}/blob/main/app.py"
|
|
28 |
SERVER_APP_PY_URL = f"{SERVER_URL}/blob/main/app.py"
|
29 |
|
30 |
# ==============================================================================
|
31 |
-
# API CALL WRAPPER FUNCTIONS (
|
32 |
# ==============================================================================
|
33 |
|
34 |
def get_creator_endpoints():
|
35 |
"""Fetches the list of supported endpoints by making an HTTP request to the Creator's JSON file."""
|
36 |
status = f"Fetching endpoint list from {CREATOR_ENDPOINTS_JSON_URL}..."
|
37 |
-
|
|
|
38 |
try:
|
39 |
response = requests.get(CREATOR_ENDPOINTS_JSON_URL, timeout=10)
|
40 |
response.raise_for_status()
|
@@ -53,56 +54,66 @@ def create_image_via_api(service_name: str, secret_data: str, available_endpoint
|
|
53 |
raise gr.Error("Please select a service and provide secret data.")
|
54 |
|
55 |
status = f"Looking up public key for '{service_name}'..."
|
56 |
-
yield
|
57 |
|
58 |
-
public_key = next((e['public_key'] for e in available_endpoints if e['name'] == service_name), None)
|
59 |
-
if not public_key:
|
60 |
-
raise gr.Error(f"Could not find public key for '{service_name}' in the fetched configuration.")
|
61 |
-
|
62 |
-
status = f"Connecting to Creator: {CREATOR_SPACE_ID}..."
|
63 |
-
yield None, None, status
|
64 |
-
|
65 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
client = Client(src=CREATOR_SPACE_ID)
|
67 |
temp_filepath = client.predict(secret_data, public_key, api_name="/create_image")
|
68 |
|
69 |
-
if not temp_filepath:
|
|
|
70 |
|
71 |
# --- PNG FIX ---
|
72 |
-
#
|
73 |
-
#
|
74 |
created_image = Image.open(temp_filepath)
|
75 |
|
76 |
-
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as png_file:
|
77 |
-
created_image.save(png_file.name, "PNG")
|
78 |
-
png_filepath = png_file.name
|
79 |
-
|
80 |
status = f"β
Success! Image created for '{service_name}'."
|
81 |
-
|
82 |
|
83 |
except Exception as e:
|
84 |
logger.error(f"Creator API call failed: {e}", exc_info=True)
|
85 |
-
|
|
|
86 |
|
87 |
def decrypt_image_via_api(image: Image.Image):
|
88 |
"""Calls the Server Space API to decrypt an image."""
|
89 |
-
if image is None:
|
|
|
|
|
90 |
status = f"Connecting to Server: {SERVER_SPACE_ID}..."
|
91 |
-
|
|
|
92 |
try:
|
93 |
client = Client(src=SERVER_SPACE_ID)
|
94 |
with io.BytesIO() as buffer:
|
|
|
95 |
image.save(buffer, format="PNG")
|
96 |
b64_string = base64.b64encode(buffer.getvalue()).decode("utf-8")
|
97 |
|
98 |
status = f"Calling API on {SERVER_SPACE_ID}..."
|
99 |
-
|
|
|
100 |
decrypted_json = client.predict(b64_string, api_name="/keylock-auth-decoder")
|
|
|
101 |
status = "β
Success! Data decrypted by the Server."
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
103 |
except Exception as e:
|
104 |
logger.error(f"Server API call failed: {e}", exc_info=True)
|
105 |
-
|
|
|
106 |
|
107 |
def generate_rsa_keys():
|
108 |
"""Generates a new RSA key pair."""
|
@@ -117,7 +128,7 @@ def generate_rsa_keys():
|
|
117 |
return private_pem, public_pem
|
118 |
|
119 |
# ==============================================================================
|
120 |
-
# GRADIO DASHBOARD INTERFACE
|
121 |
# ==============================================================================
|
122 |
theme = gr.themes.Base(
|
123 |
primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.sky, neutral_hue=gr.themes.colors.slate,
|
@@ -142,15 +153,14 @@ with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
|
142 |
with gr.Column(scale=2):
|
143 |
with gr.Row():
|
144 |
creator_service_dropdown = gr.Dropdown(label="Target Service", interactive=True, info="Select the API server you want to encrypt data for.")
|
145 |
-
refresh_button = gr.Button("π", scale=0, size="sm")
|
146 |
creator_secret_input = gr.Textbox(lines=8, label="Secret Data to Encrypt", placeholder="API_KEY: sk-123...\nUSER: demo-user")
|
147 |
creator_button = gr.Button("β¨ Create Auth Image via API", variant="primary")
|
148 |
with gr.Column(scale=1):
|
149 |
creator_status = gr.Textbox(label="Status", interactive=False, lines=2)
|
150 |
-
creator_image_output = gr.Image(label="Image from Creator Service", type="pil", show_download_button=False) # Download handled by gr.File
|
151 |
# --- PNG FIX ---
|
152 |
-
#
|
153 |
-
|
154 |
|
155 |
with gr.TabItem("β‘ Client / Decoder", id=1):
|
156 |
gr.Markdown("## Decrypt an Authentication Image")
|
@@ -186,6 +196,7 @@ with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
|
186 |
gen_keys_button.click(fn=generate_rsa_keys, inputs=None, outputs=[output_private_key, output_public_key])
|
187 |
|
188 |
def refresh_endpoints():
|
|
|
189 |
*_, last_yield = get_creator_endpoints()
|
190 |
return last_yield
|
191 |
|
@@ -195,9 +206,13 @@ with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
|
195 |
creator_button.click(
|
196 |
fn=create_image_via_api,
|
197 |
inputs=[creator_service_dropdown, creator_secret_input, endpoints_state],
|
198 |
-
outputs=[creator_image_output,
|
|
|
|
|
|
|
|
|
|
|
199 |
)
|
200 |
-
client_button.click(fn=decrypt_image_via_api, inputs=[client_image_input], outputs=[client_json_output, client_status])
|
201 |
|
202 |
if __name__ == "__main__":
|
203 |
demo.launch()
|
|
|
28 |
SERVER_APP_PY_URL = f"{SERVER_URL}/blob/main/app.py"
|
29 |
|
30 |
# ==============================================================================
|
31 |
+
# API CALL WRAPPER FUNCTIONS (CORRECTED)
|
32 |
# ==============================================================================
|
33 |
|
34 |
def get_creator_endpoints():
|
35 |
"""Fetches the list of supported endpoints by making an HTTP request to the Creator's JSON file."""
|
36 |
status = f"Fetching endpoint list from {CREATOR_ENDPOINTS_JSON_URL}..."
|
37 |
+
# Using yield for streaming status updates
|
38 |
+
yield gr.Dropdown(choices=[], value=None, label="β³ Fetching..."), status, []
|
39 |
try:
|
40 |
response = requests.get(CREATOR_ENDPOINTS_JSON_URL, timeout=10)
|
41 |
response.raise_for_status()
|
|
|
54 |
raise gr.Error("Please select a service and provide secret data.")
|
55 |
|
56 |
status = f"Looking up public key for '{service_name}'..."
|
57 |
+
# No yield here, we'll return everything at the end.
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
try:
|
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.")
|
63 |
+
|
64 |
+
status = f"Connecting to Creator: {CREATOR_SPACE_ID}..."
|
65 |
+
logger.info(status)
|
66 |
+
|
67 |
client = Client(src=CREATOR_SPACE_ID)
|
68 |
temp_filepath = client.predict(secret_data, public_key, api_name="/create_image")
|
69 |
|
70 |
+
if not temp_filepath:
|
71 |
+
raise gr.Error("Creator API did not return an image.")
|
72 |
|
73 |
# --- PNG FIX ---
|
74 |
+
# Load the image from the temp path and return the PIL Image object directly.
|
75 |
+
# The gr.Image component's `format="png"` will handle the rest.
|
76 |
created_image = Image.open(temp_filepath)
|
77 |
|
|
|
|
|
|
|
|
|
78 |
status = f"β
Success! Image created for '{service_name}'."
|
79 |
+
return created_image, status
|
80 |
|
81 |
except Exception as e:
|
82 |
logger.error(f"Creator API call failed: {e}", exc_info=True)
|
83 |
+
# On error, return an empty image and the error status.
|
84 |
+
return None, f"β Error calling Creator API: {e}"
|
85 |
|
86 |
def decrypt_image_via_api(image: Image.Image):
|
87 |
"""Calls the Server Space API to decrypt an image."""
|
88 |
+
if image is None:
|
89 |
+
raise gr.Error("Please upload an image to decrypt.")
|
90 |
+
|
91 |
status = f"Connecting to Server: {SERVER_SPACE_ID}..."
|
92 |
+
logger.info(status)
|
93 |
+
|
94 |
try:
|
95 |
client = Client(src=SERVER_SPACE_ID)
|
96 |
with io.BytesIO() as buffer:
|
97 |
+
# Explicitly save as PNG to ensure format is correct before base64 encoding
|
98 |
image.save(buffer, format="PNG")
|
99 |
b64_string = base64.b64encode(buffer.getvalue()).decode("utf-8")
|
100 |
|
101 |
status = f"Calling API on {SERVER_SPACE_ID}..."
|
102 |
+
logger.info(status)
|
103 |
+
|
104 |
decrypted_json = client.predict(b64_string, api_name="/keylock-auth-decoder")
|
105 |
+
|
106 |
status = "β
Success! Data decrypted by the Server."
|
107 |
+
logger.info(f"Decryption successful. Data: {decrypted_json}")
|
108 |
+
|
109 |
+
# --- DECRYPTED DATA FIX ---
|
110 |
+
# Use a single, final return statement. This is more robust.
|
111 |
+
return decrypted_json, status
|
112 |
+
|
113 |
except Exception as e:
|
114 |
logger.error(f"Server API call failed: {e}", exc_info=True)
|
115 |
+
# Return an empty dict and the error message for a clean UI update.
|
116 |
+
return {}, f"β Error calling Server API: {e}"
|
117 |
|
118 |
def generate_rsa_keys():
|
119 |
"""Generates a new RSA key pair."""
|
|
|
128 |
return private_pem, public_pem
|
129 |
|
130 |
# ==============================================================================
|
131 |
+
# GRADIO DASHBOARD INTERFACE (Corrected Layout and Components)
|
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,
|
|
|
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("π", scale=0, size="sm", tooltip="Refresh Target Service List")
|
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")
|
159 |
with gr.Column(scale=1):
|
160 |
creator_status = gr.Textbox(label="Status", interactive=False, lines=2)
|
|
|
161 |
# --- PNG FIX ---
|
162 |
+
# The format='png' argument tells the component's download button to create a PNG.
|
163 |
+
creator_image_output = gr.Image(label="Image from Creator Service", type="pil", show_download_button=True, format="png")
|
164 |
|
165 |
with gr.TabItem("β‘ Client / Decoder", id=1):
|
166 |
gr.Markdown("## Decrypt an Authentication Image")
|
|
|
196 |
gen_keys_button.click(fn=generate_rsa_keys, inputs=None, outputs=[output_private_key, output_public_key])
|
197 |
|
198 |
def refresh_endpoints():
|
199 |
+
# This is a generator function, so we need to iterate to get the last value.
|
200 |
*_, last_yield = get_creator_endpoints()
|
201 |
return last_yield
|
202 |
|
|
|
206 |
creator_button.click(
|
207 |
fn=create_image_via_api,
|
208 |
inputs=[creator_service_dropdown, creator_secret_input, endpoints_state],
|
209 |
+
outputs=[creator_image_output, creator_status] # Removed the gr.File output
|
210 |
+
)
|
211 |
+
client_button.click(
|
212 |
+
fn=decrypt_image_via_api,
|
213 |
+
inputs=[client_image_input],
|
214 |
+
outputs=[client_json_output, client_status]
|
215 |
)
|
|
|
216 |
|
217 |
if __name__ == "__main__":
|
218 |
demo.launch()
|