-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathchatbot.py
More file actions
378 lines (308 loc) · 14.5 KB
/
Copy pathchatbot.py
File metadata and controls
378 lines (308 loc) · 14.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
import base64
import multiprocessing
import os
import pprint
from datetime import datetime
import openai
import streamlit as st
import validators
from dotenv import load_dotenv
from PIL import Image
from streamlit_chat import message
from tools.login_checker import LoginChecker
import tldextract
import whois
def is_gov_or_corp_url(url):
# List of known government and corporate domains
GOV_DOMAINS = ["gov", "mil"]
CORP_DOMAINS = ["com", "org", "net"]
# Extract the top-level domain (TLD) of the URL
ext = tldextract.extract(url)
tld = ext.suffix
# Check if the TLD matches a known government or corporate domain
if tld in GOV_DOMAINS or tld in CORP_DOMAINS:
return True
else:
return False
def is_gov_url(url):
# Extract the domain name from the URL
domain_name = url.split("//")[-1].split("/")[0]
# Look up domain registration information using whois
domain_info = whois.whois(domain_name)
if domain_info:
try:
# Check if the domain belongs to a government entity
if 'government' in domain_info.name.lower() or 'gov' in domain_info.name.lower():
return True
except Exception:
pass
return False
def is_gov_or_corp_website(url):
# Check if the URL belongs to a government or corporate website
if is_gov_or_corp_url(url) or is_gov_url(url):
return True
else:
return False
# Change the webpage name and icon
web_icon_path = os.path.abspath("imgs/web_icon.png")
web_icon = Image.open(web_icon_path)
st.set_page_config(
page_title="RedAGPT",
page_icon=web_icon,
initial_sidebar_state="expanded",
)
# Add audio player
audio_path = os.path.abspath("audio/blade_soundtrack.mp3")
audio_file = open(audio_path, "rb")
audio_bytes = audio_file.read()
st.sidebar.audio(audio_bytes, format="audio/mp3", start_time=0)
log_dict = {"lfp": None, "ssp": None}
def add_bg_from_local(image_file):
with open(image_file, "rb") as f:
img_bytes = f.read()
st.markdown(
f"""
<style>
.stApp {{
background-image: url('data:image/png;base64,{base64.b64encode(img_bytes).decode()}');
background-size: cover;
}}
</style>
""",
unsafe_allow_html=True,
)
# Add img to the bg
bg_img_path = os.path.abspath("imgs/bg_img.jpg")
add_bg_from_local(bg_img_path)
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
openai.api_base = "https://chimeragpt.adventblocks.cc/api/v1"
st.markdown('<h1 style="color: white;">RedTeamAGPT</h1>', unsafe_allow_html=True)
if "show_first_chatbot_msg" not in st.session_state:
st.session_state["show_first_chatbot_msg"] = True
if "set_local_or_remote" not in st.session_state:
st.session_state["set_local_or_remote"] = False
if "user_local_remote" not in st.session_state:
st.session_state["user_local_remote"] = None
if "edited_local_or_remote_msg_once" not in st.session_state:
st.session_state["edited_local_or_remote_msg_once"] = False
if "show_url_msg_once" not in st.session_state:
st.session_state["show_url_msg_once"] = False
if "showed_url_msg_once" not in st.session_state:
st.session_state["showed_url_msg_once"] = False
if "showed_url_msg_once_checked" not in st.session_state:
st.session_state["showed_url_msg_once_checked"] = False
if "save_url_msg" not in st.session_state:
st.session_state["save_url_msg"] = None
# Initialize first msgs in the bot
if "bot_msgs" not in st.session_state:
st.session_state["bot_msgs"] = ["Local OR Remote"]
if "user_msgs" not in st.session_state:
st.session_state["user_msgs"] = []
if "allow_url_to_be_checked" not in st.session_state:
st.session_state["allow_url_to_be_checked"] = False
if "seek_pos" not in st.session_state:
st.session_state["seek_pos"] = None
if "process_started" not in st.session_state:
st.session_state["process_started"] = False
# Set up the event flag for disabling the user input box
if "disable_input" not in st.session_state:
st.session_state["disable_input"] = False
if "security_summary_success" not in st.session_state:
st.session_state["security_summary_success"] = []
if "security_summary_failure" not in st.session_state:
st.session_state["security_summary_failure"] = []
tools = ["Login Checker"]
model = st.selectbox("Tools", options=tools)
if model == "Login Checker":
if not st.session_state["set_local_or_remote"]:
placeholder = "Local or Remote"
else:
placeholder = "Enter URL here"
if not st.session_state["disable_input"]:
input_text = st.text_input(
"", placeholder=placeholder, key="input_text", label_visibility="hidden"
)
st.session_state["user_msgs"].append(input_text)
if not st.session_state["set_local_or_remote"]: # Local or Remote
if input_text == "Local" or input_text == "Remote":
st.session_state[
"user_local_remote"
] = input_text # save the user's input
st.session_state["set_local_or_remote"] = True
st.experimental_rerun() # Rerun the script so the "Enter URL here" can be shown in the box
else:
# show this msg in the bot only if it's not the first msg of the bot
if not st.session_state["show_first_chatbot_msg"]:
if not st.session_state["edited_local_or_remote_msg_once"]:
st.session_state["bot_msgs"][
-1
] = "THE GIVEN INPUT IS INVALID.\nGIVE Local OR Remote"
st.session_state["edited_local_or_remote_msg_once"] = True
else:
st.session_state["bot_msgs"].append(
"THE GIVEN INPUT IS INVALID.\nGIVE Local OR Remote"
)
else: # Local or Remote has been set, now URL time
# The bot should ask the user to give a url or ip based on their previous option
if not st.session_state["show_url_msg_once"]:
if st.session_state["user_local_remote"] == "Local":
msg = "GIVE URL"
else: # Remote
msg = "REMOTE SHOULD ONLY BE DONE ON IPs YOU OWN"
width = 20
padding = (width - len(msg)) // 8
centered_text = f"<div style='text-align: center;'>{' ' * padding}{msg}{' ' * padding}</div>"
decorative_lines = (
f"<div style='text-align: center;'>{'💀' * width}</div>"
)
# Combine the decorative lines and centered text
msg = f"{decorative_lines * 2}<br>{centered_text}<br>{decorative_lines * 2}"
# Streamlit gets confused here, so I assign the msg to a session
# instead of doing len(st.session_state["bot_msgs"][-1])
# where I show it on the bottom of the script
st.session_state["save_url_msg"] = msg
st.session_state["show_url_msg_once"] = True
st.experimental_rerun() # Rerun script to show the url msg in the bot
if not st.session_state["allow_url_to_be_checked"]:
# check for gov or corp
if validators.url(input_text) and not is_gov_or_corp_website(input_text):
st.session_state["allow_url_to_be_checked"] = True
else:
# Edit the url msg from "GIVE URL" TO "THE GIVEN URL IS INVALID"
# as we show one response from the bot and one from the user for each interaction
# and as we provide the "GIVE URL" to direct the user to give a url
# then won't be able to get a response by the bot based on the user's input
# thus, the needed change but it only need to be done once
if (
st.session_state["showed_url_msg_once"]
and not st.session_state["showed_url_msg_once_checked"]
):
st.error("THE GIVEN URL IS INVALID OR FORBIDDEN!")
st.session_state["showed_url_msg_once_checked"] = True
else:
st.session_state["bot_msgs"].append("GOOD JOB. YOUR OPTION HAS BEEN SET.")
if st.session_state["allow_url_to_be_checked"]:
with st.spinner(f"Testing website {input_text}. This will take a while."):
if not st.session_state["process_started"]:
lgcheck = LoginChecker(input_text)
process = multiprocessing.Process(
target=lgcheck.run()
)
process.start()
process.join()
st.session_state["process_started"] = True
process.join()
if not process.is_alive():
st.session_state["process_started"] = False
if os.path.exists(lgcheck.summary_file_path):
login_checker_msg = "Login Checker process has completed."
st.success(login_checker_msg)
# st.session_state["security_summary_success"].append(
# login_checker_msg
# )
st.success(lgcheck.autogpt_resp)
# st.session_state["security_summary_success"].append(
# lgcheck.autogpt_resp
# )
with open(lgcheck.summary_file_path, "r") as sectxt:
summary = "".join(sectxt.readlines())
st.success(summary)
# st.session_state["security_summary_success"].append(summary)
else:
login_checker_msg = "Login Check failed. No report found."
st.error(login_checker_msg)
# st.session_state["security_summary_failure"].append(
# login_checker_msg
# )
st.error(lgcheck.autogpt_resp)
# st.session_state["security_summary_failure"].append(
# lgcheck.autogpt_resp
# )
with st.expander("debug log"):
if os.path.exists(lgcheck.logging_file_path):
with open(lgcheck.logging_file_path, "r") as runtxt:
formatted_readlines = ''.join(runtxt.readlines())
st.write(formatted_readlines)
st.session_state["disable_input"] = True # Disable input
# st.experimental_rerun()
else:
if len(st.session_state["security_summary_failure"]) != 0:
st.error(st.session_state["security_summary_failure"])
else:
for item in st.session_state["security_summary_success"]:
st.success(item)
st.warning("SESSION EXPIRED.\nREFRESH THE PAGE.")
# Check that the security report is not created yet
if not st.session_state["disable_input"]:
# Show the first msg in the chatbot
if st.session_state["show_first_chatbot_msg"]:
message(
st.session_state["bot_msgs"], key=str(len(st.session_state["bot_msgs"]) - 1)
)
st.session_state["show_first_chatbot_msg"] = False
else: # all other times
# Show the "GIVE URL" msg in the chatbot
if (
st.session_state["show_url_msg_once"]
and not st.session_state["showed_url_msg_once"]
):
st.session_state["bot_msgs"].append(st.session_state["save_url_msg"])
# message(
# st.session_state["save_url_msg"],
# key=str(len(st.session_state["bot_msgs"])),
# )
st.markdown(st.session_state["save_url_msg"], unsafe_allow_html=True)
st.session_state["showed_url_msg_once"] = True
else:
# Show all msgs after the first msg is already shown
# Filter out any empty entry from the user
filtered_user_msgs1 = [
(i, msg)
for i, msg in enumerate(st.session_state["user_msgs"])
if len(msg) != 0
]
filtered_bot_msgs1 = [
(i, msg)
for i, msg in enumerate(st.session_state["bot_msgs"])
if len(msg) != 0
]
# If the two lists do not have the same
# Decrease the size of the longer list by one
# so they can match
filtered_user_msgs2 = filtered_user_msgs1
filtered_bot_msgs2 = filtered_bot_msgs1
if len(filtered_user_msgs1) > len(filtered_bot_msgs1):
filtered_user_msgs2 = filtered_user_msgs1[:-1]
elif len(filtered_user_msgs1) < len(filtered_bot_msgs1):
filtered_bot_msgs2 = filtered_bot_msgs1[:-1]
# Initialize the flag
executed_once = False
# Match the elements
for (user_i, user_msg), (bot_i, bot_msg) in reversed(
list(zip(filtered_user_msgs2, filtered_bot_msgs2))
):
if not executed_once and (
len(filtered_user_msgs2) != len(filtered_bot_msgs2)
):
# Show the last element that was filtered above
if len(filtered_user_msgs2) > len(filtered_bot_msgs2):
message(
filtered_user_msgs2[user_i + 1][
1
], # Extract message text from the tuple
is_user=True,
key=str(user_i + 1) + "_user",
)
elif len(filtered_user_msgs2) < len(filtered_bot_msgs2):
message(
filtered_bot_msgs2[bot_i + 1][
1
], # Extract message text from the tuple
key=str(bot_i + 1),
)
# For showing the extra element only once and first in the conversation
executed_once = True
# Print the matched elements
message(user_msg, is_user=True, key=str(user_i) + "_user")
message(bot_msg, key=str(bot_i))