Spaces:
Paused
Paused
improve logging
Browse files
app.py
CHANGED
@@ -20,23 +20,38 @@ openai_api_key = os.getenv("OPENAI_API_KEY")
|
|
20 |
discord_webhook_url_public = os.getenv("DISCORD_WEBHOOK_URL_PUBLIC")
|
21 |
discord_webhook_url_easy = os.getenv("DISCORD_WEBHOOK_URL_EASY")
|
22 |
discord_webhook_url_hard = os.getenv("DISCORD_WEBHOOK_URL_HARD")
|
23 |
-
captcha_site_key = os.getenv(
|
24 |
-
|
25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
|
27 |
secret_key = os.getenv("CTF_SECRET_KEY", "ctf_secret_key")
|
28 |
hard_challenge_secret = os.getenv("HARD_CHALLENGE_SECRET", "hard_challenge_secret")
|
29 |
hf_ctf_sync_token = os.getenv("HF_CTF_SYNC_TOKEN")
|
30 |
|
|
|
31 |
class Env(str, Enum):
|
32 |
PLAYGROUND = "playground"
|
33 |
CHALLENGE_EASY = "ctf_easy"
|
34 |
CHALLENGE_HARD = "ctf_hard"
|
35 |
|
|
|
36 |
DB_FILE = "./reviews.db"
|
37 |
|
38 |
INITIAL_DATA = {
|
39 |
-
"Discord username": [
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
"Feedback": [
|
41 |
"I work at ABC, and i liked your product!",
|
42 |
"I was confused as I thought Invariant Labs works on NFTs?",
|
@@ -59,17 +74,25 @@ repo = huggingface_hub.Repository(
|
|
59 |
repo.git_pull()
|
60 |
shutil.copyfile("./hf_data/reviews.db", DB_FILE)
|
61 |
|
|
|
62 |
def backup_db():
|
63 |
db = sqlite3.connect(DB_FILE)
|
64 |
cur = db.cursor()
|
65 |
shutil.copyfile(DB_FILE, "./hf_data/reviews.db")
|
66 |
for level in [Env.PLAYGROUND, Env.CHALLENGE_EASY, Env.CHALLENGE_HARD]:
|
67 |
reviews = cur.execute(f"SELECT * FROM {level.value}").fetchall()
|
68 |
-
pd_data = pd.DataFrame(
|
69 |
-
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
db.close()
|
72 |
|
|
|
73 |
# Create table if it doesn't already exist
|
74 |
def create_tables():
|
75 |
db = sqlite3.connect(DB_FILE)
|
@@ -90,7 +113,14 @@ def create_tables():
|
|
90 |
|
91 |
# Add review to the db
|
92 |
def add_review_db(level: str, name: str, feedback: str, summary: str):
|
93 |
-
print(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
db = sqlite3.connect(DB_FILE)
|
95 |
cur = db.cursor()
|
96 |
cur.execute(
|
@@ -110,7 +140,7 @@ def get_today_utc():
|
|
110 |
|
111 |
|
112 |
def get_code(username: str):
|
113 |
-
today = get_today_utc() - timedelta(hours=8)
|
114 |
date_string = today.strftime("%Y-%m-%d")
|
115 |
alphabet = string.ascii_letters + string.digits
|
116 |
data = f"{secret_key}||{username}||{date_string}||{secret_key}"
|
@@ -146,6 +176,7 @@ def rows_to_text(rows: list[list[str]]) -> str:
|
|
146 |
text += "\t".join(row) + "\n"
|
147 |
return text
|
148 |
|
|
|
149 |
def get_summary(rows: list[list[str]]) -> str:
|
150 |
text = rows_to_text(rows)
|
151 |
prompt = f"{system_prompt}\n{text}"
|
@@ -187,7 +218,10 @@ def summary(webhook_url, disable_discord, env, username, state):
|
|
187 |
if not disable_discord:
|
188 |
webhook_url = webhook_url or discord_webhook_url_public
|
189 |
try:
|
190 |
-
r = requests.post(
|
|
|
|
|
|
|
191 |
r.raise_for_status()
|
192 |
except Exception:
|
193 |
return "Error: webhook discord failed"
|
@@ -195,15 +229,21 @@ def summary(webhook_url, disable_discord, env, username, state):
|
|
195 |
webhook_url = discord_webhook_url_easy
|
196 |
try:
|
197 |
chunk = ""
|
198 |
-
for word in summary.split(
|
199 |
if len(word) + 1 + len(chunk) < 1700:
|
200 |
chunk += word + " "
|
201 |
else:
|
202 |
-
r = requests.post(
|
|
|
|
|
|
|
203 |
r.raise_for_status()
|
204 |
chunk = ""
|
205 |
if chunk:
|
206 |
-
r = requests.post(
|
|
|
|
|
|
|
207 |
r.raise_for_status()
|
208 |
except Exception:
|
209 |
return "Error: webhook discord failed"
|
@@ -240,7 +280,9 @@ def summary_ch_easy(webhook_url, disable_discord, username, state):
|
|
240 |
return result
|
241 |
|
242 |
|
243 |
-
def summary_ch_hard(
|
|
|
|
|
244 |
if len(username) > 50:
|
245 |
gr.Warning("Username too long (max 50 characters)")
|
246 |
return
|
@@ -285,7 +327,9 @@ def run_summary_hard():
|
|
285 |
|
286 |
new_rows = []
|
287 |
# add rows from initial data to random place in the table
|
288 |
-
for username, feedback in zip(
|
|
|
|
|
289 |
new_rows.append([username, feedback])
|
290 |
# replace secret in new row 3
|
291 |
code = get_code(hard_challenge_secret)
|
@@ -303,21 +347,28 @@ def run_summary_hard():
|
|
303 |
|
304 |
try:
|
305 |
chunk = ""
|
306 |
-
for word in summary.split(
|
307 |
if len(word) + 1 + len(chunk) < 1700:
|
308 |
chunk += word + " "
|
309 |
else:
|
310 |
-
r = requests.post(
|
|
|
|
|
|
|
311 |
r.raise_for_status()
|
312 |
print("hard chall chunk: ", chunk)
|
313 |
chunk = ""
|
314 |
if chunk:
|
315 |
print("hard chall chunk: ", chunk)
|
316 |
-
r = requests.post(
|
|
|
|
|
|
|
317 |
r.raise_for_status()
|
318 |
except Exception:
|
319 |
return "Error: webhook discord failed"
|
320 |
|
|
|
321 |
js_code = """
|
322 |
(function() {
|
323 |
globalThis.setStorage = (key, value)=>{
|
@@ -367,10 +418,13 @@ with gr.Blocks(
|
|
367 |
theme=gr.themes.Soft(font="NeueMontreal"),
|
368 |
css=css,
|
369 |
) as demo:
|
370 |
-
gr.HTML(
|
|
|
371 |
<img src="https://invariantlabs.ai/theme/images/logo.svg" alt="logo" style="vertical-align: middle; display: inline-block;">
|
372 |
<span style="vertical-align: middle;">invariantlabs.ai - Security Challenge Summer 2024</span>
|
373 |
-
</h1>""",
|
|
|
|
|
374 |
|
375 |
initial_table = initialize_table()
|
376 |
playground_state = gr.State(initial_table)
|
@@ -392,7 +446,9 @@ with gr.Blocks(
|
|
392 |
feedback_pg = gr.Textbox(label="Feedback")
|
393 |
with gr.Column():
|
394 |
summary_output = gr.Textbox(
|
395 |
-
label="Summary output",
|
|
|
|
|
396 |
)
|
397 |
|
398 |
generate_summary_playground = gr.Button("Submit")
|
@@ -404,9 +460,9 @@ with gr.Blocks(
|
|
404 |
|
405 |
with gr.Column():
|
406 |
playground_password = gr.Textbox(
|
407 |
-
label="Playground SECRET_PASSWORD",
|
408 |
info="Here you can modify value of the secret password",
|
409 |
-
value=get_random_code()
|
410 |
)
|
411 |
|
412 |
with gr.Column():
|
@@ -560,7 +616,9 @@ with gr.Blocks(
|
|
560 |
if __name__ == "__main__":
|
561 |
scheduler = BackgroundScheduler()
|
562 |
scheduler.add_job(func=backup_db, trigger="interval", seconds=600)
|
563 |
-
scheduler.add_job(
|
|
|
|
|
564 |
# scheduler.add_job(func=run_summary_hard, trigger=CronTrigger(hour="*/1", timezone=timezone.utc))
|
565 |
scheduler.start()
|
566 |
create_tables()
|
|
|
20 |
discord_webhook_url_public = os.getenv("DISCORD_WEBHOOK_URL_PUBLIC")
|
21 |
discord_webhook_url_easy = os.getenv("DISCORD_WEBHOOK_URL_EASY")
|
22 |
discord_webhook_url_hard = os.getenv("DISCORD_WEBHOOK_URL_HARD")
|
23 |
+
captcha_site_key = os.getenv(
|
24 |
+
"CAPTCHA_SITE_KEY", "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
|
25 |
+
)
|
26 |
+
captcha_secret_key = os.getenv(
|
27 |
+
"CAPTCHA_SECRET_KEY", "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
|
28 |
+
)
|
29 |
+
system_prompt = os.getenv(
|
30 |
+
"SYSTEM_PROMPT",
|
31 |
+
"Read all received user feedback and summarize three most positive comments:",
|
32 |
+
)
|
33 |
|
34 |
secret_key = os.getenv("CTF_SECRET_KEY", "ctf_secret_key")
|
35 |
hard_challenge_secret = os.getenv("HARD_CHALLENGE_SECRET", "hard_challenge_secret")
|
36 |
hf_ctf_sync_token = os.getenv("HF_CTF_SYNC_TOKEN")
|
37 |
|
38 |
+
|
39 |
class Env(str, Enum):
|
40 |
PLAYGROUND = "playground"
|
41 |
CHALLENGE_EASY = "ctf_easy"
|
42 |
CHALLENGE_HARD = "ctf_hard"
|
43 |
|
44 |
+
|
45 |
DB_FILE = "./reviews.db"
|
46 |
|
47 |
INITIAL_DATA = {
|
48 |
+
"Discord username": [
|
49 |
+
"User123",
|
50 |
+
"Bob",
|
51 |
+
"i_love_invariant",
|
52 |
+
"DISAPPOINTED_USER_55",
|
53 |
+
"",
|
54 |
+
],
|
55 |
"Feedback": [
|
56 |
"I work at ABC, and i liked your product!",
|
57 |
"I was confused as I thought Invariant Labs works on NFTs?",
|
|
|
74 |
repo.git_pull()
|
75 |
shutil.copyfile("./hf_data/reviews.db", DB_FILE)
|
76 |
|
77 |
+
|
78 |
def backup_db():
|
79 |
db = sqlite3.connect(DB_FILE)
|
80 |
cur = db.cursor()
|
81 |
shutil.copyfile(DB_FILE, "./hf_data/reviews.db")
|
82 |
for level in [Env.PLAYGROUND, Env.CHALLENGE_EASY, Env.CHALLENGE_HARD]:
|
83 |
reviews = cur.execute(f"SELECT * FROM {level.value}").fetchall()
|
84 |
+
pd_data = pd.DataFrame(
|
85 |
+
reviews, columns=["id", "timestamp", "name", "feedback", "summary"]
|
86 |
+
)
|
87 |
+
pd_data.to_csv(
|
88 |
+
f"./hf_data/data/reviews_{level.value}-00000-of-00001.csv", index=False
|
89 |
+
)
|
90 |
+
repo.push_to_hub(
|
91 |
+
blocking=False, commit_message=f"Updating data at {datetime.now()}"
|
92 |
+
)
|
93 |
db.close()
|
94 |
|
95 |
+
|
96 |
# Create table if it doesn't already exist
|
97 |
def create_tables():
|
98 |
db = sqlite3.connect(DB_FILE)
|
|
|
113 |
|
114 |
# Add review to the db
|
115 |
def add_review_db(level: str, name: str, feedback: str, summary: str):
|
116 |
+
print(
|
117 |
+
f"add_review_db:\n"
|
118 |
+
f"Level: {level}\n"
|
119 |
+
f"Name: {name}\n"
|
120 |
+
f"Feedback:\n{feedback}\n"
|
121 |
+
f"Summary:\n{summary}\n"
|
122 |
+
f"{'-' * 40}"
|
123 |
+
)
|
124 |
db = sqlite3.connect(DB_FILE)
|
125 |
cur = db.cursor()
|
126 |
cur.execute(
|
|
|
140 |
|
141 |
|
142 |
def get_code(username: str):
|
143 |
+
today = get_today_utc() - timedelta(hours=8) # offset for UTC 8:00 starting time
|
144 |
date_string = today.strftime("%Y-%m-%d")
|
145 |
alphabet = string.ascii_letters + string.digits
|
146 |
data = f"{secret_key}||{username}||{date_string}||{secret_key}"
|
|
|
176 |
text += "\t".join(row) + "\n"
|
177 |
return text
|
178 |
|
179 |
+
|
180 |
def get_summary(rows: list[list[str]]) -> str:
|
181 |
text = rows_to_text(rows)
|
182 |
prompt = f"{system_prompt}\n{text}"
|
|
|
218 |
if not disable_discord:
|
219 |
webhook_url = webhook_url or discord_webhook_url_public
|
220 |
try:
|
221 |
+
r = requests.post(
|
222 |
+
webhook_url,
|
223 |
+
json={"content": summary, "allowed_mentions": {"parse": []}},
|
224 |
+
)
|
225 |
r.raise_for_status()
|
226 |
except Exception:
|
227 |
return "Error: webhook discord failed"
|
|
|
229 |
webhook_url = discord_webhook_url_easy
|
230 |
try:
|
231 |
chunk = ""
|
232 |
+
for word in summary.split(" "):
|
233 |
if len(word) + 1 + len(chunk) < 1700:
|
234 |
chunk += word + " "
|
235 |
else:
|
236 |
+
r = requests.post(
|
237 |
+
webhook_url,
|
238 |
+
json={"content": chunk, "allowed_mentions": {"parse": []}},
|
239 |
+
)
|
240 |
r.raise_for_status()
|
241 |
chunk = ""
|
242 |
if chunk:
|
243 |
+
r = requests.post(
|
244 |
+
webhook_url,
|
245 |
+
json={"content": chunk, "allowed_mentions": {"parse": []}},
|
246 |
+
)
|
247 |
r.raise_for_status()
|
248 |
except Exception:
|
249 |
return "Error: webhook discord failed"
|
|
|
280 |
return result
|
281 |
|
282 |
|
283 |
+
def summary_ch_hard(
|
284 |
+
g_recaptcha_response, webhook_url, disable_discord, username, state
|
285 |
+
):
|
286 |
if len(username) > 50:
|
287 |
gr.Warning("Username too long (max 50 characters)")
|
288 |
return
|
|
|
327 |
|
328 |
new_rows = []
|
329 |
# add rows from initial data to random place in the table
|
330 |
+
for username, feedback in zip(
|
331 |
+
INITIAL_DATA["Discord username"][:-1], INITIAL_DATA["Feedback"][:-1]
|
332 |
+
):
|
333 |
new_rows.append([username, feedback])
|
334 |
# replace secret in new row 3
|
335 |
code = get_code(hard_challenge_secret)
|
|
|
347 |
|
348 |
try:
|
349 |
chunk = ""
|
350 |
+
for word in summary.split(" "):
|
351 |
if len(word) + 1 + len(chunk) < 1700:
|
352 |
chunk += word + " "
|
353 |
else:
|
354 |
+
r = requests.post(
|
355 |
+
discord_webhook_url_hard,
|
356 |
+
json={"content": chunk, "allowed_mentions": {"parse": []}},
|
357 |
+
)
|
358 |
r.raise_for_status()
|
359 |
print("hard chall chunk: ", chunk)
|
360 |
chunk = ""
|
361 |
if chunk:
|
362 |
print("hard chall chunk: ", chunk)
|
363 |
+
r = requests.post(
|
364 |
+
discord_webhook_url_hard,
|
365 |
+
json={"content": chunk, "allowed_mentions": {"parse": []}},
|
366 |
+
)
|
367 |
r.raise_for_status()
|
368 |
except Exception:
|
369 |
return "Error: webhook discord failed"
|
370 |
|
371 |
+
|
372 |
js_code = """
|
373 |
(function() {
|
374 |
globalThis.setStorage = (key, value)=>{
|
|
|
418 |
theme=gr.themes.Soft(font="NeueMontreal"),
|
419 |
css=css,
|
420 |
) as demo:
|
421 |
+
gr.HTML(
|
422 |
+
"""<h1 style="display: inline-block; vertical-align: middle;">
|
423 |
<img src="https://invariantlabs.ai/theme/images/logo.svg" alt="logo" style="vertical-align: middle; display: inline-block;">
|
424 |
<span style="vertical-align: middle;">invariantlabs.ai - Security Challenge Summer 2024</span>
|
425 |
+
</h1>""",
|
426 |
+
elem_id="invariant-header",
|
427 |
+
)
|
428 |
|
429 |
initial_table = initialize_table()
|
430 |
playground_state = gr.State(initial_table)
|
|
|
446 |
feedback_pg = gr.Textbox(label="Feedback")
|
447 |
with gr.Column():
|
448 |
summary_output = gr.Textbox(
|
449 |
+
label="Summary output",
|
450 |
+
interactive=False,
|
451 |
+
lines=6,
|
452 |
)
|
453 |
|
454 |
generate_summary_playground = gr.Button("Submit")
|
|
|
460 |
|
461 |
with gr.Column():
|
462 |
playground_password = gr.Textbox(
|
463 |
+
label="Playground SECRET_PASSWORD",
|
464 |
info="Here you can modify value of the secret password",
|
465 |
+
value=get_random_code(),
|
466 |
)
|
467 |
|
468 |
with gr.Column():
|
|
|
616 |
if __name__ == "__main__":
|
617 |
scheduler = BackgroundScheduler()
|
618 |
scheduler.add_job(func=backup_db, trigger="interval", seconds=600)
|
619 |
+
scheduler.add_job(
|
620 |
+
func=run_summary_hard, trigger=CronTrigger(hour=8, timezone=timezone.utc)
|
621 |
+
)
|
622 |
# scheduler.add_job(func=run_summary_hard, trigger=CronTrigger(hour="*/1", timezone=timezone.utc))
|
623 |
scheduler.start()
|
624 |
create_tables()
|