-
Notifications
You must be signed in to change notification settings - Fork 2
/
vis.py
executable file
·236 lines (197 loc) · 6.76 KB
/
vis.py
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
#!/usr/bin/env python
from rich import print
from pyvis.network import Network, Node
import networkx as nx
import random
import database as db
import itertools
from typer import Typer
IMPORTED = True
app = Typer()
colors = [
"#C724B1",
"#71DBD4",
"#642F6C",
"#58A7AF",
"#B3B0C4",
"#3A3A59",
"#59CBE8",
"#1E22AA",
"#00BCE1",
]
OUTPUT_PATH = "/tmp"
OMIT_PLAYERS = ["BYOCTF_Automaton#7840"]
def make_net():
net = Network(
height="900px",
width="100%",
directed=True,
notebook=False,
select_menu=True,
filter_menu=True,
neighborhood_highlight=True,
bgcolor="#414199",
font_color="#E93CAC",
cdn_resources="remote",
)
# net.show_buttons()
net.show_buttons(filter_=["physics"])
return net
# net.toggle_physics(False)
@app.command()
def all_reports():
# players and teams
nxGraph = nx.DiGraph() # other types of graphs
players()
# challenge relationships
nxGraph = nx.MultiDiGraph() # other types of graphs
challs()
# inter-player tips
trans(trans_type="tip")
@app.command()
def trans(trans_type: str = "tip", user: str | None = None):
net = make_net()
nxGraph = nx.MultiDiGraph() # other types of graphs
with db.db_session:
# for player in db.select(u for u in db.User):
bot = db.User.get(name="BYOCTF_Automaton#7840")
if user != None:
user = db.User.get(name=user)
if user == None:
print("user not found")
return "user not found"
trans: db.Transaction
if trans_type in ["*", "all"]:
all_trans = db.select(t for t in db.Transaction)[:]
else:
all_trans = db.select(t for t in db.Transaction if t.type == trans_type)[:]
avg_trans = sum([t.value for t in all_trans]) / len(all_trans)
# print(avg_trans)
len_all_trans = len(all_trans)
for trans in all_trans:
if trans.value == 0:
print('invalid transaction', trans)
continue
if user != None:
if user.id not in [trans.sender.id, trans.recipient.id]:
continue
title = f"""
Num of sent transactions: {db.select(t for t in db.Transaction if t.sender == trans.sender ).count()}
Num of recv transactions: {db.select(t for t in db.Transaction if t.recipient == trans.sender ).count()}
""".strip()
# print(f'trans id {trans.id} - sender "{trans.sender.name}" recipient "{trans.recipient.name}" amount {trans.value}')
nxGraph.add_node(trans.sender.name, title=title)
nxGraph.add_edge(
trans.sender.name,
trans.recipient.name,
weight=min(avg_trans / trans.value, 20),
type=trans.type,
) # type: ignore
# nxGraph.add_node(trans.sender.name, sender=trans.sender.name, )
# nxGraph.add_node(trans.recipient.name, sender=trans.recipient.name)
net.from_nx(nxGraph)
# net.show_buttons()
# net.filter_menu
if IMPORTED:
net.write_html("/tmp/trans_net.html")
with open("/tmp/trans_net.html") as f:
return f.read()
net.show(
f"{OUTPUT_PATH}/inter-player_transactions_{trans_type}.html", notebook=False
)
@app.command()
def players():
net = make_net()
nxGraph = nx.MultiDiGraph() # other types of graphs
with db.db_session:
all_teams = db.select(t for t in db.Team if t.name != "__botteam__")[:]
len_all_teams = len(all_teams)
avg_score = db.average_score()
for idx, team in enumerate(all_teams):
title = f"""
Team Name: {team.name}
Team ID: {team.id}
Team UUID: {team.uuid}
Team members: {', '.join([p.name for p in team.members])}
""".strip()
nxGraph.add_node(
team.name,
size=25,
color="#c1ae09",
font="20px arial black",
uuid=str(team.uuid),
title=title,
)
for player in team.members:
score = db.getScore(player)
# print(player, score)
nxGraph.add_node(
player.name,
size=max(max(score, 1) // max(score, 1), 10),
color=random.choice(colors),
group=idx,
)
nxGraph.add_edge(player.name, team.name)
net.from_nx(nxGraph)
# net.show_buttons()
# net.filter_menu
if IMPORTED:
net.write_html("/tmp/players_net.html")
with open("/tmp/players_net.html") as f:
return f.read()
net.show(f"{OUTPUT_PATH}/challenge_relationships.html", notebook=False)
@app.command()
def challs(chall: str | None = None):
"""chall is the uuid of the challenge"""
net = make_net()
nxGraph = nx.MultiDiGraph() # other types of graphs
with db.db_session:
chall: db.Challenge
if chall != None:
filtering = True
chall = db.Challenge.get(uuid=chall)
if chall == None:
print("challenge not found")
return "challenge not found"
if chall != None:
challs = db.select(c for c in db.Challenge if c == chall)[:]
else:
challs = db.select(c for c in db.Challenge)[:]
len_challs = len(challs)
for idx, chall in enumerate(challs):
title = f"""
Challenge Title: {chall.title}
Challenge ID: {chall.id}
Challenge UUID: {chall.uuid}
Challenge Author: {chall.author.name}
Number of flags: {len(chall.flags)}
""".strip()
relations = 0
relations += len(chall.children)
relations += len(chall.parent)
color = colors[relations % len(colors)] # Example logic
nxGraph.add_node(
chall.title,
label=f"{chall.title}",
color=color,
author=chall.author.name,
title=title,
group=idx,
)
for parent in chall.parent:
nxGraph.add_node(parent.title, label=parent.title, group=idx)
nxGraph.add_edge(
parent.title, chall.title, weight=relations / len_challs
) # this is the correct way to express child parent relationships ; test by dev reset and looking at the relationship of small number of challs
net.from_nx(nxGraph)
# net.show_buttons()
# net.filter_menu
if IMPORTED:
net.write_html("/tmp/challs_net.html")
with open("/tmp/challs_net.html") as f:
return f.read()
net.show(f"{OUTPUT_PATH}/players_and_teams.html", notebook=False)
if __name__ == "__main__":
# IMPORTED = False
net = make_net()
app()