Last active
November 28, 2023 15:01
-
-
Save SteelCrow/963ef64ebf5a9b0081c7805f6e5dabe0 to your computer and use it in GitHub Desktop.
Anti-Quishing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from qreader import QReader | |
import gradio as gr | |
# Pandas helps us with data transformation into DataFrame | |
# for further use in BarPlot UI widget | |
import pandas as pd | |
import vt | |
# Main class of our recogniser and segmentator | |
qreader = QReader() | |
# Our workhorse function | |
async def detect_and_decode_qr_code(vt_key, img): | |
# Array of invisible BarPlots if something goes wrong | |
analysis = [ | |
gr.BarPlot(visible=False), | |
gr.BarPlot(visible=False), | |
gr.BarPlot(visible=False), | |
gr.BarPlot(visible=False), | |
] | |
try: | |
decoded = qreader.detect_and_decode(img) | |
# We handle only one QR code in the picture | |
# that's why we check result for type | |
if decoded is not None and type(decoded) is tuple: | |
# Prepare the VirusTotal client class | |
async with vt.Client(vt_key) as client: | |
# Iterate through all potential links in | |
# the QR coode | |
for idx in range(len(decoded)): | |
# Because we have only 4 pre-defined | |
# widgets | |
if idx > 4: | |
break | |
# Ask VirusTotal about the URL | |
res = await client.scan_url_async( | |
decoded[idx], wait_for_completion=True | |
) | |
# Transform the verdict from VT to a | |
# pandas DataFrame because we have no other | |
# option to provide it to the BarPlot widget | |
df = pd.DataFrame( | |
res.stats.items(), | |
columns=["categories", "values"] | |
) | |
# Create BarPlot | |
anylisis[idx] = gr.BarPlot( | |
df, | |
x="categories", | |
y="values", | |
color="categories", | |
vertical=False, | |
visible=True, | |
scale=2, | |
width=600, | |
height=500, | |
) | |
return analysis | |
except Exception as e: | |
# Awful error handling, but it's sufficient for PoC | |
print(e) | |
# Always return an array of invisible BarPlot widgets | |
# in case of errors | |
return analysis | |
# Clear the state of widgets | |
def reset_state(img, i0, i1, i2, i3): | |
return ( | |
gr.update(value=None), | |
gr.update(value=""), | |
gr.update(value=""), | |
gr.update(value=""), | |
gr.update(value=""), | |
) | |
# Gradio interface description | |
with gr.Blocks() as app: | |
with gr.Row(): | |
with gr.Column(): | |
# Sensitive info! We create textbox input | |
# only for quick prototyping; always | |
# use secret management | |
# solution in production | |
vt_key = gr.Textbox(label="Virus Total Key", type="password") | |
img_in = gr.Image() | |
reset = gr.Button("Reset") | |
# Ugly hack for multi-link case in QR code, | |
# Gradio does not support dynamic widgets | |
# so we have to allocate them beforehand | |
with gr.Column(): | |
output0 = gr.BarPlot(visible=False) | |
output1 = gr.BarPlot(visible=False) | |
output2 = gr.BarPlot(visible=False) | |
output3 = gr.BarPlot(visible=False) | |
# Make interface alive; when you drop or select | |
# an image for analysis it will automatically run our | |
# function and return results | |
img_in.change( | |
detect_and_decode_qr_code, | |
[vt_key, img_in], | |
[output0, output1, output2, output3], | |
) | |
# To eliminate some pesky bugs in interface, | |
# clear the state of widgets | |
reset.click( | |
reset_state, | |
[img_in, output0, output1, output2, output3], | |
[img_in, output0, output1, output2, output3], | |
) | |
app.launch() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment