Update app.py
Browse files
app.py
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
def generate_rsa_keys():
|
| 2 |
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
| 3 |
private_pem = private_key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()).decode('utf-8')
|
|
@@ -93,4 +121,76 @@ def send_keylock_wrapper(service_name: str, image: Image.Image, available_endpoi
|
|
| 93 |
def refresh_and_update_all():
|
| 94 |
for dropdown_update, status_update, state_update in get_server_list():
|
| 95 |
pass
|
| 96 |
-
return dropdown_update, dropdown_update, status_update, state_update
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 3 |
+
import base64
|
| 4 |
+
import io
|
| 5 |
+
import json
|
| 6 |
+
import logging
|
| 7 |
+
import os
|
| 8 |
+
import requests
|
| 9 |
+
import struct
|
| 10 |
+
import numpy as np
|
| 11 |
+
from cryptography.hazmat.primitives import serialization
|
| 12 |
+
from cryptography.hazmat.primitives.asymmetric import rsa, padding
|
| 13 |
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
| 14 |
+
from cryptography.hazmat.primitives import hashes
|
| 15 |
+
|
| 16 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
| 17 |
+
logger = logging.getLogger(__name__)
|
| 18 |
+
|
| 19 |
+
CREATOR_ENDPOINTS_JSON_URL = "https://huggingface.co/spaces/broadfield-dev/KeyLock-Auth-Creator/raw/main/endpoints.json"
|
| 20 |
+
BASE_HF_URL = "https://huggingface.co/spaces/"
|
| 21 |
+
CREATOR_SPACE_ID = "broadfield-dev/KeyLock-Auth-Creator"
|
| 22 |
+
SERVER_SPACE_ID = "broadfield-dev/KeyLock-Auth-Server"
|
| 23 |
+
CREATOR_URL = f"{BASE_HF_URL}{CREATOR_SPACE_ID}"
|
| 24 |
+
SERVER_URL = f"{BASE_HF_URL}{SERVER_SPACE_ID}"
|
| 25 |
+
CREATOR_APP_PY_URL = f"{CREATOR_URL}/raw/main/app.py"
|
| 26 |
+
SERVER_APP_PY_URL = f"{SERVER_URL}/raw/main/app.py"
|
| 27 |
+
|
| 28 |
+
|
| 29 |
def generate_rsa_keys():
|
| 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')
|
|
|
|
| 121 |
def refresh_and_update_all():
|
| 122 |
for dropdown_update, status_update, state_update in get_server_list():
|
| 123 |
pass
|
| 124 |
+
return dropdown_update, dropdown_update, status_update, state_update
|
| 125 |
+
|
| 126 |
+
theme = gr.themes.Base(
|
| 127 |
+
primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.sky, neutral_hue=gr.themes.colors.slate,
|
| 128 |
+
font=(gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"),
|
| 129 |
+
).set(
|
| 130 |
+
body_background_fill="#F1F5F9", panel_background_fill="white", block_background_fill="white",
|
| 131 |
+
block_border_width="1px", block_shadow="*shadow_drop_lg",
|
| 132 |
+
button_primary_background_fill="*primary_600", button_primary_background_fill_hover="*primary_700",
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
with gr.Blocks(theme=theme, title="KeyLock Operations Dashboard") as demo:
|
| 136 |
+
endpoints_state = gr.State([])
|
| 137 |
+
|
| 138 |
+
gr.Markdown("# π KeyLock Operations Dashboard")
|
| 139 |
+
gr.Markdown("A centralized dashboard to manage and demonstrate the entire KeyLock ecosystem. Key/Image creation is performed locally, while decryption is handled by a **live, remote API call** to a secure server.")
|
| 140 |
+
|
| 141 |
+
with gr.Tabs() as tabs:
|
| 142 |
+
with gr.TabItem("β Create KeyLock", id=0):
|
| 143 |
+
gr.Markdown("## Step 1: Create an Encrypted Authentication Image (Local)")
|
| 144 |
+
gr.Markdown(f"This tool acts as the **Auth Creator**. It fetches a list of available servers from a public [configuration file]({CREATOR_ENDPOINTS_JSON_URL}), then uses the selected server's public key to encrypt your data into a PNG. **This entire creation process happens locally.**")
|
| 145 |
+
with gr.Row(variant="panel"):
|
| 146 |
+
with gr.Column(scale=2):
|
| 147 |
+
with gr.Row():
|
| 148 |
+
creator_service_dropdown = gr.Dropdown(label="Target Server", interactive=True, info="Select the API server to encrypt data for.")
|
| 149 |
+
refresh_button = gr.Button("π", scale=0, size="sm", tooltip="Refresh Server List from Config File")
|
| 150 |
+
creator_secret_input = gr.Textbox(lines=8, label="Secret Data to Encrypt", placeholder="API_KEY: sk-123...\nUSER: demo-user")
|
| 151 |
+
creator_button = gr.Button("β¨ Create Auth Image", variant="primary")
|
| 152 |
+
with gr.Column(scale=1):
|
| 153 |
+
creator_status = gr.Textbox(label="Status", interactive=False, lines=2)
|
| 154 |
+
creator_image_output = gr.Image(label="Generated Encrypted Image", type="pil", show_download_button=True, format="png")
|
| 155 |
+
|
| 156 |
+
with gr.TabItem("β‘ Send KeyLock", id=1):
|
| 157 |
+
gr.Markdown("## Step 2: Decrypt via Live API Call")
|
| 158 |
+
gr.Markdown("This tool acts as the **Client**. It sends the encrypted image you created in Step 1 to the live, remote **Decoder Server** you select from the same configuration list. The server uses its securely stored private key to decrypt the data and sends the result back.")
|
| 159 |
+
with gr.Row(variant="panel"):
|
| 160 |
+
with gr.Column(scale=1):
|
| 161 |
+
gr.Markdown("### Configuration")
|
| 162 |
+
send_service_dropdown = gr.Dropdown(label="Target Server", interactive=True, info="Select the API server to send the image to.")
|
| 163 |
+
gr.Markdown("### Image to Send")
|
| 164 |
+
client_image_input = gr.Image(type="pil", label="Upload or Drag Encrypted Image Here", sources=["upload", "clipboard"])
|
| 165 |
+
client_button = gr.Button("π Decrypt via Remote Server", variant="primary")
|
| 166 |
+
with gr.Column(scale=1):
|
| 167 |
+
gr.Markdown("### Response from Server")
|
| 168 |
+
client_status = gr.Textbox(label="Status", interactive=False, lines=2)
|
| 169 |
+
client_json_output = gr.JSON(label="Decrypted Data")
|
| 170 |
+
|
| 171 |
+
with gr.TabItem("βΉοΈ Info & Key Generation", id=2):
|
| 172 |
+
gr.Markdown("## Ecosystem Architecture")
|
| 173 |
+
gr.Markdown(f"This dashboard uses a public [configuration file]({CREATOR_ENDPOINTS_JSON_URL}) to dynamically discover and interact with live services. It demonstrates a secure, decoupled workflow.")
|
| 174 |
+
with gr.Row():
|
| 175 |
+
with gr.Column():
|
| 176 |
+
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})")
|
| 177 |
+
with gr.Column():
|
| 178 |
+
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})")
|
| 179 |
+
|
| 180 |
+
with gr.Accordion("π RSA Key Pair Generator", open=False):
|
| 181 |
+
gr.Markdown("Create a new key pair. In a real scenario, you would add the **Public Key** and the server's **API Endpoint URL** to the `endpoints.json` configuration file, and set the **Private Key** as a secret variable in the corresponding server space.")
|
| 182 |
+
with gr.Row():
|
| 183 |
+
with gr.Column():
|
| 184 |
+
output_public_key = gr.Textbox(lines=10, label="Generated Public Key", interactive=False, show_copy_button=True)
|
| 185 |
+
with gr.Column():
|
| 186 |
+
output_private_key = gr.Textbox(lines=10, label="Generated Private Key", interactive=False, show_copy_button=True)
|
| 187 |
+
gen_keys_button = gr.Button("βοΈ Generate New 2048-bit Key Pair", variant="secondary")
|
| 188 |
+
|
| 189 |
+
gen_keys_button.click(fn=generate_rsa_keys, inputs=None, outputs=[output_private_key, output_public_key])
|
| 190 |
+
refresh_button.click(fn=refresh_and_update_all, outputs=[creator_service_dropdown, send_service_dropdown, creator_status, endpoints_state])
|
| 191 |
+
demo.load(fn=refresh_and_update_all, outputs=[creator_service_dropdown, send_service_dropdown, creator_status, endpoints_state])
|
| 192 |
+
creator_button.click(fn=create_keylock_wrapper, inputs=[creator_service_dropdown, creator_secret_input, endpoints_state], outputs=[creator_image_output, creator_status])
|
| 193 |
+
client_button.click(fn=send_keylock_wrapper, inputs=[send_service_dropdown, client_image_input, endpoints_state], outputs=[client_json_output, client_status])
|
| 194 |
+
|
| 195 |
+
if __name__ == "__main__":
|
| 196 |
+
demo.launch()
|