Update gradio_keylock/component.py
Browse files- gradio_keylock/component.py +154 -27
gradio_keylock/component.py
CHANGED
@@ -164,49 +164,176 @@ class AppServerLogic:
|
|
164 |
return priv, pub
|
165 |
|
166 |
class KeylockDecoderComponent:
|
167 |
-
def __init__(self, server_logic
|
168 |
self.server_logic = server_logic
|
169 |
self.image_input = None
|
170 |
self.status_display = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
|
172 |
-
def
|
173 |
-
|
174 |
-
|
175 |
-
self.status_display = gr.Markdown("Upload a KeyLock image to auto-fill credentials.")
|
176 |
-
with gr.Accordion("Generate Encrypted Image", open=False):
|
177 |
-
payload_input = gr.Textbox(
|
178 |
-
label="Payload to Encrypt (Demo)",
|
179 |
-
placeholder="USER = \"demo-user\"\nPASS: DEMO_test_PASS\n# Lines starting with # are ignored",
|
180 |
-
lines=5,
|
181 |
-
value="""
|
182 |
-
USER = "TestUser"
|
183 |
-
PASS: TestPass
|
184 |
-
"GROQ_API_KEY" = "ALKSDFJASHFKSFH"
|
185 |
-
"HF_API_KEY" : "SDFLSDJFFIEWOIFHOWI"
|
186 |
-
"OPENAI_API_KEY" : SDFLSJDSFSDF
|
187 |
-
""",
|
188 |
-
)
|
189 |
-
generate_img_button = gr.Button("Generate Image", variant="secondary")
|
190 |
-
generated_image_preview = gr.Image(label="Generated Image Preview", type="filepath", interactive=False)
|
191 |
-
generated_file_download = gr.File(label="Download Uncorrupted PNG", interactive=False)
|
192 |
-
with gr.Accordion("Create New Standalone Key Pair", open=False):
|
193 |
-
generate_keys_button = gr.Button("Generate Keys", variant="secondary")
|
194 |
-
with gr.Row():
|
195 |
-
output_private_key = gr.Code(label="Generated Private Key", language="python")
|
196 |
-
output_public_key = gr.Code(label="Generated Public Key", language="python")
|
197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
def generate_wrapper(kv_string):
|
199 |
payload_dict = self.server_logic._parse_kv_string(kv_string)
|
200 |
return self.server_logic.generate_encrypted_image(payload_dict)
|
201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
generate_img_button.click(
|
203 |
fn=generate_wrapper,
|
204 |
inputs=[payload_input],
|
205 |
outputs=[generated_image_preview, generated_file_download]
|
206 |
)
|
|
|
207 |
generate_keys_button.click(
|
208 |
fn=self.server_logic.generate_pem_keys,
|
209 |
inputs=None,
|
210 |
outputs=[output_private_key, output_public_key]
|
211 |
)
|
212 |
-
|
|
|
|
164 |
return priv, pub
|
165 |
|
166 |
class KeylockDecoderComponent:
|
167 |
+
def __init__(self, server_logic):
|
168 |
self.server_logic = server_logic
|
169 |
self.image_input = None
|
170 |
self.status_display = None
|
171 |
+
|
172 |
+
self.CSS = """
|
173 |
+
#login-container {
|
174 |
+
max-width: 480px;
|
175 |
+
margin: 4rem auto !important;
|
176 |
+
padding: 2rem 2.5rem;
|
177 |
+
background-color: rgba(22, 27, 34, 0.85);
|
178 |
+
border: 1px solid #30363d;
|
179 |
+
border-radius: 12px;
|
180 |
+
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
|
181 |
+
}
|
182 |
+
#keylock-logo {
|
183 |
+
text-align: center;
|
184 |
+
font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
|
185 |
+
color: #c9d1d9;
|
186 |
+
margin-bottom: 1.5rem;
|
187 |
+
}
|
188 |
+
#keylock-logo svg {
|
189 |
+
width: 48px;
|
190 |
+
height: 48px;
|
191 |
+
fill: #58a6ff;
|
192 |
+
margin-bottom: 0.75rem;
|
193 |
+
}
|
194 |
+
#keylock-logo h1 {
|
195 |
+
font-size: 24px;
|
196 |
+
font-weight: 600;
|
197 |
+
margin: 0;
|
198 |
+
}
|
199 |
+
#image-upload-box {
|
200 |
+
background-color: #0d1117 !important;
|
201 |
+
border: 2px dashed #30363d !important;
|
202 |
+
border-radius: 8px !important;
|
203 |
+
min-height: 220px;
|
204 |
+
transition: border-color 0.2s ease-in-out, background-color 0.2s ease-in-out;
|
205 |
+
}
|
206 |
+
#image-upload-box:hover {
|
207 |
+
border-color: #58a6ff !important;
|
208 |
+
background-color: #161b22 !important;
|
209 |
+
}
|
210 |
+
#image-upload-box .!h-full.w-full > div:first-of-type {
|
211 |
+
display: flex;
|
212 |
+
align-items: center;
|
213 |
+
justify-content: center;
|
214 |
+
color: #8b949e;
|
215 |
+
}
|
216 |
+
#status-display {
|
217 |
+
text-align: center;
|
218 |
+
padding: 1rem;
|
219 |
+
border-radius: 6px;
|
220 |
+
margin-top: 1rem;
|
221 |
+
min-height: 50px;
|
222 |
+
background-color: #161b22;
|
223 |
+
border: 1px solid #30363d;
|
224 |
+
transition: all 0.3s ease;
|
225 |
+
}
|
226 |
+
#status-display ul {
|
227 |
+
list-style-type: none;
|
228 |
+
padding: 0;
|
229 |
+
margin: 0.5rem 0 0 0;
|
230 |
+
text-align: left;
|
231 |
+
}
|
232 |
+
#status-display li {
|
233 |
+
background-color: #0d1117;
|
234 |
+
padding: 0.5rem;
|
235 |
+
margin-top: 0.5rem;
|
236 |
+
border-radius: 4px;
|
237 |
+
border: 1px solid #30363d;
|
238 |
+
}
|
239 |
+
.tool-accordion {
|
240 |
+
border-color: #30363d !important;
|
241 |
+
background-color: #0d1117 !important;
|
242 |
+
border-radius: 8px !important;
|
243 |
+
margin-top: 1.5rem;
|
244 |
+
}
|
245 |
+
.tool-accordion > .label-wrap {
|
246 |
+
background-color: #161b22 !important;
|
247 |
+
}
|
248 |
+
"""
|
249 |
|
250 |
+
def _handle_login_attempt(self, image_input: Image.Image):
|
251 |
+
if image_input is None:
|
252 |
+
return gr.update(value='<p style="color:#8b949e;">Awaiting KeyLock image...</p>', visible=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
|
254 |
+
result = self.server_logic.decode_payload(image_input)
|
255 |
+
|
256 |
+
if result["status"] == "Success":
|
257 |
+
payload_html = "<ul>"
|
258 |
+
for key, value in result['payload'].items():
|
259 |
+
value_display = "•" * len(str(value)) if "pass" in key.lower() else value
|
260 |
+
payload_html += f"<li><strong>{key}:</strong> {value_display}</li>"
|
261 |
+
payload_html += "</ul>"
|
262 |
+
|
263 |
+
return gr.update(
|
264 |
+
value=f'<div style="color:#3fb950;">'
|
265 |
+
f'<h4>Authentication Success</h4>'
|
266 |
+
f'{payload_html}'
|
267 |
+
f'</div>',
|
268 |
+
visible=True
|
269 |
+
)
|
270 |
+
else:
|
271 |
+
return gr.update(
|
272 |
+
value=f'<p style="color:#f85149;"><strong>Login Failed:</strong> {result["message"]}</p>',
|
273 |
+
visible=True
|
274 |
+
)
|
275 |
+
|
276 |
+
def build_ui(self):
|
277 |
+
with gr.Column(elem_id="login-container"):
|
278 |
+
gr.HTML("""
|
279 |
+
<div id="keylock-logo">
|
280 |
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM9 6c0-1.66 1.34-3 3-3s3 1.34 3 3v2H9V6zm9 14H6V10h12v10zm-6-3c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"></path></svg>
|
281 |
+
<h1>KeyLock Authentication</h1>
|
282 |
+
</div>
|
283 |
+
""")
|
284 |
+
|
285 |
+
self.image_input = gr.Image(
|
286 |
+
label="KeyLock Image",
|
287 |
+
type="pil",
|
288 |
+
show_label=False,
|
289 |
+
elem_id="image-upload-box"
|
290 |
+
)
|
291 |
+
|
292 |
+
self.status_display = gr.HTML(
|
293 |
+
'<p style="color:#8b949e;">Upload a KeyLock image to authenticate.</p>',
|
294 |
+
elem_id="status-display"
|
295 |
+
)
|
296 |
+
|
297 |
+
with gr.Accordion("Generator Tools", open=False, elem_classes=["tool-accordion"]):
|
298 |
+
with gr.Tabs():
|
299 |
+
with gr.TabItem("Encrypt Payload"):
|
300 |
+
payload_input = gr.Textbox(
|
301 |
+
label="Data to Encrypt (Key=Value format)",
|
302 |
+
placeholder="USER = \"demo-user\"\nPASS: DEMO_test_PASS\n# Lines starting with # are ignored",
|
303 |
+
lines=5,
|
304 |
+
value="""USER = "TestUser"\nPASS: TestPass\n"GROQ_API_KEY" = "ALKSDFJASHFKSFH" """,
|
305 |
+
)
|
306 |
+
generate_img_button = gr.Button("Generate Encrypted Image", variant="primary")
|
307 |
+
generated_image_preview = gr.Image(label="Generated Image Preview", type="filepath", interactive=False)
|
308 |
+
generated_file_download = gr.File(label="Download Uncorrupted PNG", interactive=False)
|
309 |
+
|
310 |
+
with gr.TabItem("Create Key Pair"):
|
311 |
+
gr.Markdown("Create a new standalone RSA-2048 key pair.")
|
312 |
+
generate_keys_button = gr.Button("Generate Keys", variant="secondary")
|
313 |
+
with gr.Row():
|
314 |
+
output_private_key = gr.Code(label="Generated Private Key", language="pem", interactive=False)
|
315 |
+
output_public_key = gr.Code(label="Generated Public Key", language="pem", interactive=False)
|
316 |
+
|
317 |
def generate_wrapper(kv_string):
|
318 |
payload_dict = self.server_logic._parse_kv_string(kv_string)
|
319 |
return self.server_logic.generate_encrypted_image(payload_dict)
|
320 |
|
321 |
+
self.image_input.upload(
|
322 |
+
fn=self._handle_login_attempt,
|
323 |
+
inputs=[self.image_input],
|
324 |
+
outputs=[self.status_display]
|
325 |
+
)
|
326 |
+
|
327 |
generate_img_button.click(
|
328 |
fn=generate_wrapper,
|
329 |
inputs=[payload_input],
|
330 |
outputs=[generated_image_preview, generated_file_download]
|
331 |
)
|
332 |
+
|
333 |
generate_keys_button.click(
|
334 |
fn=self.server_logic.generate_pem_keys,
|
335 |
inputs=None,
|
336 |
outputs=[output_private_key, output_public_key]
|
337 |
)
|
338 |
+
|
339 |
+
return self.image_input, self.status_display
|