new: Initial commit to mark body responses as legitimate/malicious

pull/86/head
Raphaël Vinot 2020-08-20 19:39:03 +02:00
parent fc7cb77002
commit c5aabcf4a3
5 changed files with 178 additions and 58 deletions

View File

@ -114,21 +114,22 @@ class Indexing():
pipeline = self.redis.pipeline() pipeline = self.redis.pipeline()
for urlnode in crawled_tree.root_hartree.url_tree.traverse(): for urlnode in crawled_tree.root_hartree.url_tree.traverse():
if not urlnode.empty_response: if urlnode.empty_response:
pipeline.zincrby('body_hashes', 1, urlnode.body_hash) continue
pipeline.zincrby(f'bh|{urlnode.body_hash}', 1, urlnode.hostname) pipeline.zincrby('body_hashes', 1, urlnode.body_hash)
# set of all captures with this hash pipeline.zincrby(f'bh|{urlnode.body_hash}', 1, urlnode.hostname)
pipeline.sadd(f'bh|{urlnode.body_hash}|captures', crawled_tree.uuid) # set of all captures with this hash
# ZSet of all urlnode_UUIDs|full_url pipeline.sadd(f'bh|{urlnode.body_hash}|captures', crawled_tree.uuid)
pipeline.zincrby(f'bh|{urlnode.body_hash}|captures|{crawled_tree.uuid}', 1, f'{urlnode.uuid}|{urlnode.hostnode_uuid}|{urlnode.name}') # ZSet of all urlnode_UUIDs|full_url
if hasattr(urlnode, 'embedded_ressources') and urlnode.embedded_ressources: pipeline.zincrby(f'bh|{urlnode.body_hash}|captures|{crawled_tree.uuid}', 1, f'{urlnode.uuid}|{urlnode.hostnode_uuid}|{urlnode.name}')
for mimetype, blobs in urlnode.embedded_ressources.items(): if hasattr(urlnode, 'embedded_ressources') and urlnode.embedded_ressources:
for h, body in blobs: for mimetype, blobs in urlnode.embedded_ressources.items():
pipeline.zincrby('body_hashes', 1, h) for h, body in blobs:
pipeline.zincrby(f'bh|{h}', 1, urlnode.hostname) pipeline.zincrby('body_hashes', 1, h)
pipeline.sadd(f'bh|{h}|captures', crawled_tree.uuid) pipeline.zincrby(f'bh|{h}', 1, urlnode.hostname)
pipeline.zincrby(f'bh|{h}|captures|{crawled_tree.uuid}', 1, pipeline.sadd(f'bh|{h}|captures', crawled_tree.uuid)
f'{urlnode.uuid}|{urlnode.hostnode_uuid}|{urlnode.name}') pipeline.zincrby(f'bh|{h}|captures|{crawled_tree.uuid}', 1,
f'{urlnode.uuid}|{urlnode.hostnode_uuid}|{urlnode.name}')
pipeline.execute() pipeline.execute()
@ -146,6 +147,54 @@ class Indexing():
def get_body_hash_domains(self, body_hash: str) -> List[Tuple[str, float]]: def get_body_hash_domains(self, body_hash: str) -> List[Tuple[str, float]]:
return self.redis.zrevrange(f'bh|{body_hash}', 0, -1, withscores=True) return self.redis.zrevrange(f'bh|{body_hash}', 0, -1, withscores=True)
def legitimate_capture(self, crawled_tree: CrawledTree) -> None:
pipeline = self.redis.pipeline()
for urlnode in crawled_tree.root_hartree.url_tree.traverse():
if urlnode.empty_response:
continue
pipeline.sadd(f'bh|{urlnode.body_hash}|legitimate', urlnode.hostname)
pipeline.execute()
def legitimate_hostnode(self, hostnode: HostNode) -> None:
pipeline = self.redis.pipeline()
for urlnode in hostnode.urls:
if urlnode.empty_response:
continue
pipeline.sadd(f'bh|{urlnode.body_hash}|legitimate', urlnode.hostname)
pipeline.execute()
def legitimate_urlnode(self, urlnode: URLNode) -> None:
if urlnode.empty_response:
return
self.redis.sadd(f'bh|{urlnode.body_hash}|legitimate', urlnode.hostname)
def is_legitimate(self, urlnode: URLNode) -> Optional[bool]:
hostnames = self.redis.smembers(f'bh|{urlnode.body_hash}|legitimate')
if hostnames:
if urlnode.hostname in hostnames:
return True # Legitimate
return False # Malicious
elif self.redis.sismember('bh|malicious', urlnode.body_hash):
return False
return None # Unknown
def malicious_node(self, urlnode: URLNode) -> None:
if urlnode.empty_response:
return None
self.redis.sadd('bh|malicious', urlnode.body_hash)
def is_malicious(self, urlnode: URLNode) -> Optional[bool]:
if urlnode.empty_response:
return None
if self.redis.sismember('bh|malicious', urlnode.body_hash):
return True
legitimate = self.is_legitimate(urlnode)
if legitimate is True:
return False
if legitimate is False:
return True
return None
class Lookyloo(): class Lookyloo():
@ -259,6 +308,31 @@ class Lookyloo():
return ct return ct
def add_to_legitimate(self, capture_uuid: str, hostnode_uuid: Optional[str]=None, urlnode_uuid: Optional[str]=None):
ct = self.get_crawled_tree(capture_uuid)
if not hostnode_uuid and not urlnode_uuid:
self.indexing.legitimate_capture(ct)
return
if hostnode_uuid:
hostnode = ct.root_hartree.get_host_node_by_uuid(hostnode_uuid)
self.indexing.legitimate_hostnode(hostnode)
if urlnode_uuid:
urlnode = ct.root_hartree.get_url_node_by_uuid(urlnode_uuid)
self.indexing.legitimate_urlnode(urlnode)
def bodies_legitimacy_check(self, tree: CrawledTree) -> CrawledTree:
hostnodes_with_malicious_content = set()
for urlnode in tree.root_hartree.url_tree.traverse():
malicious = self.indexing.is_malicious(urlnode)
if malicious is not None:
urlnode.add_feature('malicious', malicious)
hostnodes_with_malicious_content.add(urlnode.hostnode_uuid)
for hostnode_with_malicious_content in hostnodes_with_malicious_content:
hostnode = tree.root_hartree.get_host_node_by_uuid(hostnode_with_malicious_content)
hostnode.add_feature('malicious', malicious)
return tree
def load_tree(self, capture_uuid: str) -> Tuple[str, str, str, str, Dict[str, str]]: def load_tree(self, capture_uuid: str) -> Tuple[str, str, str, str, Dict[str, str]]:
capture_dir = self.lookup_capture_dir(capture_uuid) capture_dir = self.lookup_capture_dir(capture_uuid)
if not capture_dir: if not capture_dir:
@ -268,6 +342,7 @@ class Lookyloo():
with open((capture_dir / 'meta'), 'r') as f: with open((capture_dir / 'meta'), 'r') as f:
meta = json.load(f) meta = json.load(f)
ct = self.get_crawled_tree(capture_uuid) ct = self.get_crawled_tree(capture_uuid)
ct = self.bodies_legitimacy_check(ct)
return ct.to_json(), ct.start_time.isoformat(), ct.user_agent, ct.root_url, meta return ct.to_json(), ct.start_time.isoformat(), ct.user_agent, ct.root_url, meta
def remove_pickle(self, capture_uuid: str) -> None: def remove_pickle(self, capture_uuid: str) -> None:

64
poetry.lock generated
View File

@ -140,7 +140,7 @@ description = "Foreign Function Interface for Python calling C code."
name = "cffi" name = "cffi"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.14.1" version = "1.14.2"
[package.dependencies] [package.dependencies]
pycparser = "*" pycparser = "*"
@ -580,7 +580,7 @@ description = "Library for building powerful interactive command lines in Python
name = "prompt-toolkit" name = "prompt-toolkit"
optional = false optional = false
python-versions = ">=3.6.1" python-versions = ">=3.6.1"
version = "3.0.5" version = "3.0.6"
[package.dependencies] [package.dependencies]
wcwidth = "*" wcwidth = "*"
@ -1186,34 +1186,34 @@ certifi = [
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
] ]
cffi = [ cffi = [
{file = "cffi-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:66dd45eb9530e3dde8f7c009f84568bc7cac489b93d04ac86e3111fb46e470c2"}, {file = "cffi-1.14.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82"},
{file = "cffi-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:4f53e4128c81ca3212ff4cf097c797ab44646a40b42ec02a891155cd7a2ba4d8"}, {file = "cffi-1.14.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4"},
{file = "cffi-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:833401b15de1bb92791d7b6fb353d4af60dc688eaa521bd97203dcd2d124a7c1"}, {file = "cffi-1.14.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e"},
{file = "cffi-1.14.1-cp27-cp27m-win32.whl", hash = "sha256:26f33e8f6a70c255767e3c3f957ccafc7f1f706b966e110b855bfe944511f1f9"}, {file = "cffi-1.14.2-cp27-cp27m-win32.whl", hash = "sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c"},
{file = "cffi-1.14.1-cp27-cp27m-win_amd64.whl", hash = "sha256:b87dfa9f10a470eee7f24234a37d1d5f51e5f5fa9eeffda7c282e2b8f5162eb1"}, {file = "cffi-1.14.2-cp27-cp27m-win_amd64.whl", hash = "sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1"},
{file = "cffi-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:effd2ba52cee4ceff1a77f20d2a9f9bf8d50353c854a282b8760ac15b9833168"}, {file = "cffi-1.14.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7"},
{file = "cffi-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bac0d6f7728a9cc3c1e06d4fcbac12aaa70e9379b3025b27ec1226f0e2d404cf"}, {file = "cffi-1.14.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c"},
{file = "cffi-1.14.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d6033b4ffa34ef70f0b8086fd4c3df4bf801fee485a8a7d4519399818351aa8e"}, {file = "cffi-1.14.2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731"},
{file = "cffi-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8416ed88ddc057bab0526d4e4e9f3660f614ac2394b5e019a628cdfff3733849"}, {file = "cffi-1.14.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0"},
{file = "cffi-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:892daa86384994fdf4856cb43c93f40cbe80f7f95bb5da94971b39c7f54b3a9c"}, {file = "cffi-1.14.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e"},
{file = "cffi-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:c991112622baee0ae4d55c008380c32ecfd0ad417bcd0417ba432e6ba7328caa"}, {file = "cffi-1.14.2-cp35-cp35m-win32.whl", hash = "sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487"},
{file = "cffi-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fcf32bf76dc25e30ed793145a57426064520890d7c02866eb93d3e4abe516948"}, {file = "cffi-1.14.2-cp35-cp35m-win_amd64.whl", hash = "sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad"},
{file = "cffi-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f960375e9823ae6a07072ff7f8a85954e5a6434f97869f50d0e41649a1c8144f"}, {file = "cffi-1.14.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2"},
{file = "cffi-1.14.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a6d28e7f14ecf3b2ad67c4f106841218c8ab12a0683b1528534a6c87d2307af3"}, {file = "cffi-1.14.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123"},
{file = "cffi-1.14.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cda422d54ee7905bfc53ee6915ab68fe7b230cacf581110df4272ee10462aadc"}, {file = "cffi-1.14.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1"},
{file = "cffi-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:4a03416915b82b81af5502459a8a9dd62a3c299b295dcdf470877cb948d655f2"}, {file = "cffi-1.14.2-cp36-cp36m-win32.whl", hash = "sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281"},
{file = "cffi-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:4ce1e995aeecf7cc32380bc11598bfdfa017d592259d5da00fc7ded11e61d022"}, {file = "cffi-1.14.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4"},
{file = "cffi-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e23cb7f1d8e0f93addf0cae3c5b6f00324cccb4a7949ee558d7b6ca973ab8ae9"}, {file = "cffi-1.14.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798"},
{file = "cffi-1.14.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ddff0b2bd7edcc8c82d1adde6dbbf5e60d57ce985402541cd2985c27f7bec2a0"}, {file = "cffi-1.14.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4"},
{file = "cffi-1.14.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f90c2267101010de42f7273c94a1f026e56cbc043f9330acd8a80e64300aba33"}, {file = "cffi-1.14.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f"},
{file = "cffi-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:3cd2c044517f38d1b577f05927fb9729d3396f1d44d0c659a445599e79519792"}, {file = "cffi-1.14.2-cp37-cp37m-win32.whl", hash = "sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650"},
{file = "cffi-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fa72a52a906425416f41738728268072d5acfd48cbe7796af07a923236bcf96"}, {file = "cffi-1.14.2-cp37-cp37m-win_amd64.whl", hash = "sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15"},
{file = "cffi-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:267adcf6e68d77ba154334a3e4fc921b8e63cbb38ca00d33d40655d4228502bc"}, {file = "cffi-1.14.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa"},
{file = "cffi-1.14.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d3148b6ba3923c5850ea197a91a42683f946dba7e8eb82dfa211ab7e708de939"}, {file = "cffi-1.14.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c"},
{file = "cffi-1.14.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:98be759efdb5e5fa161e46d404f4e0ce388e72fbf7d9baf010aff16689e22abe"}, {file = "cffi-1.14.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75"},
{file = "cffi-1.14.1-cp38-cp38-win32.whl", hash = "sha256:6923d077d9ae9e8bacbdb1c07ae78405a9306c8fd1af13bfa06ca891095eb995"}, {file = "cffi-1.14.2-cp38-cp38-win32.whl", hash = "sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e"},
{file = "cffi-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:b1d6ebc891607e71fd9da71688fcf332a6630b7f5b7f5549e6e631821c0e5d90"}, {file = "cffi-1.14.2-cp38-cp38-win_amd64.whl", hash = "sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c"},
{file = "cffi-1.14.1.tar.gz", hash = "sha256:b2a2b0d276a136146e012154baefaea2758ef1f56ae9f4e01c612b0831e0bd2f"}, {file = "cffi-1.14.2.tar.gz", hash = "sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b"},
] ]
chardet = [ chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
@ -1453,8 +1453,8 @@ pluggy = [
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
] ]
prompt-toolkit = [ prompt-toolkit = [
{file = "prompt_toolkit-3.0.5-py3-none-any.whl", hash = "sha256:df7e9e63aea609b1da3a65641ceaf5bc7d05e0a04de5bd45d05dbeffbabf9e04"}, {file = "prompt_toolkit-3.0.6-py3-none-any.whl", hash = "sha256:683397077a64cd1f750b71c05afcfc6612a7300cb6932666531e5a54f38ea564"},
{file = "prompt_toolkit-3.0.5.tar.gz", hash = "sha256:563d1a4140b63ff9dd587bda9557cffb2fe73650205ab6f4383092fb882e7dc8"}, {file = "prompt_toolkit-3.0.6.tar.gz", hash = "sha256:7630ab85a23302839a0f26b31cc24f518e6155dea1ed395ea61b42c45941b6a6"},
] ]
protego = [ protego = [
{file = "Protego-0.1.16.tar.gz", hash = "sha256:a682771bc7b51b2ff41466460896c1a5a653f9a1e71639ef365a72e66d8734b4"}, {file = "Protego-0.1.16.tar.gz", hash = "sha256:a682771bc7b51b2ff41466460896c1a5a653f9a1e71639ef365a72e66d8734b4"},

View File

@ -492,6 +492,16 @@ def body_hash_details(body_hash: str):
return render_template('body_hash.html', body_hash=body_hash, domains=domains, captures=captures) return render_template('body_hash.html', body_hash=body_hash, domains=domains, captures=captures)
@app.route('/tree/<string:tree_uuid>/mark_as_legitimate', methods=['POST'])
def mark_as_legitimate(tree_uuid: str):
if request.data:
legitimate_entries = request.get_json(force=True)
lookyloo.add_to_legitimate(tree_uuid, **legitimate_entries)
else:
lookyloo.add_to_legitimate(tree_uuid)
return jsonify({'message': 'Legitimate entry added.'})
# Query API # Query API
@app.route('/json/<string:tree_uuid>/redirects', methods=['GET']) @app.route('/json/<string:tree_uuid>/redirects', methods=['GET'])

View File

@ -161,6 +161,13 @@ function UnflagAllNodes() {
.on('mouseout', () => d3.select('#tooltip').style('opacity', 0)); .on('mouseout', () => d3.select('#tooltip').style('opacity', 0));
}; };
function MarkAsLegitimate(capture_uuid, hostnode_uuid=null, urlnode_uuid=null) {
let data = {};
if (hostnode_uuid != null) { data['hostnode_uuid'] = hostnode_uuid; };
if (urlnode_uuid != null) { data['urlnode_uuid'] = urlnode_uuid; };
$.post(`/tree/${capture_uuid}/mark_as_legitimate`, data);
};
function UnflagHostNode(hostnode_uuid) { function UnflagHostNode(hostnode_uuid) {
d3.select(`#node_${hostnode_uuid}`).select('rect').style('fill', 'white'); d3.select(`#node_${hostnode_uuid}`).select('rect').style('fill', 'white');
d3.select(`#node_${hostnode_uuid}`).select('text').style('fill', 'black'); d3.select(`#node_${hostnode_uuid}`).select('text').style('fill', 'black');
@ -320,15 +327,13 @@ function update(root, computed_node_width=0) {
// Set background based on the computed width and height // Set background based on the computed width and height
let background = main_svg.insert('rect', ':first-child') let background = main_svg.insert('rect', ':first-child')
.attr('y', 0) .attr('y', 0)
// FIXME: + 200 doesn't make much sense... .attr('width', newWidth + (margin.right + margin.left)*2)
.attr('width', newWidth + margin.right + margin.left + 200)
.attr('height', newHeight + margin.top + margin.bottom) .attr('height', newHeight + margin.top + margin.bottom)
.style('fill', "url(#backstripes)"); .style('fill', "url(#backstripes)");
// Update size // Update size
d3.select("body svg") main_svg
// FIXME: + 200 doesn't make much sense... .attr("width", newWidth + (margin.right + margin.left)*2)
.attr("width", newWidth + margin.right + margin.left + 200)
.attr("height", newHeight + margin.top + margin.bottom) .attr("height", newHeight + margin.top + margin.bottom)
// Update pattern // Update pattern
@ -445,14 +450,14 @@ function update(root, computed_node_width=0) {
}) })
.on('mouseout', () => d3.select('#tooltip').style('opacity', 0)); .on('mouseout', () => d3.select('#tooltip').style('opacity', 0));
const http_icon_size = 24;
if (d.data.http_content) { if (d.data.http_content) {
const icon_size = 24;
// set lock insecure connection // set lock insecure connection
d3.select(this).append("svg").append('rect') d3.select(this).append("svg").append('rect')
.attr('x', selected_node_bbox.width - 22) .attr('x', selected_node_bbox.width - 22)
.attr('y', selected_node_bbox.height - 13) .attr('y', selected_node_bbox.height - 13)
.attr('width', icon_size) .attr('width', http_icon_size)
.attr('height', icon_size) .attr('height', http_icon_size)
.attr('fill', 'white') .attr('fill', 'white')
.attr('stroke', 'black'); .attr('stroke', 'black');
@ -460,8 +465,8 @@ function update(root, computed_node_width=0) {
.attr('x', selected_node_bbox.width - 22) .attr('x', selected_node_bbox.width - 22)
.attr('y', selected_node_bbox.height - 13) .attr('y', selected_node_bbox.height - 13)
.attr('id', 'insecure_image') .attr('id', 'insecure_image')
.attr("width", icon_size) .attr("width", http_icon_size)
.attr("height", icon_size) .attr("height", http_icon_size)
.attr("xlink:href", '/static/insecure.svg') .attr("xlink:href", '/static/insecure.svg')
.on('mouseover', () => { .on('mouseover', () => {
d3.select('#tooltip') d3.select('#tooltip')
@ -472,6 +477,33 @@ function update(root, computed_node_width=0) {
}) })
.on('mouseout', () => d3.select('#tooltip').style('opacity', 0)); .on('mouseout', () => d3.select('#tooltip').style('opacity', 0));
}; };
const malicious_icon_size = 24;
if (d.data.malicious) {
// set lock insecure connection
d3.select(this).append("svg").append('rect')
.attr('x', selected_node_bbox.width - 22 - http_icon_size)
.attr('y', selected_node_bbox.height - 13)
.attr('width', malicious_icon_size)
.attr('height', malicious_icon_size)
.attr('fill', 'white')
.attr('stroke', 'black');
d3.select(this).append('image')
.attr('x', selected_node_bbox.width - 22 - http_icon_size)
.attr('y', selected_node_bbox.height - 13)
.attr('id', 'insecure_image')
.attr("width", malicious_icon_size)
.attr("height", malicious_icon_size)
.attr("xlink:href", '/static/bomb.svg')
.on('mouseover', () => {
d3.select('#tooltip')
.style('opacity', 1)
.style('left', `${d3.event.pageX + 10}px`)
.style('top', `${d3.event.pageY + 10}px`)
.text('This node containts known malicious content');
})
.on('mouseout', () => d3.select('#tooltip').style('opacity', 0));
};
}); });
return node_group; return node_group;

View File

@ -93,7 +93,7 @@
</li> </li>
{% endif %} {% endif %}
<li> <li>
<a href="#unflag" role="button" onclick="UnflagAllNodes();">Unflag all nodes</a> <a href="#/" role="button" onclick="UnflagAllNodes();">Unflag all nodes</a>
</li> </li>
<li> <li>
<a href="{{ url_for('image', tree_uuid=tree_uuid) }}" role="button">Download screenshot</a> <a href="{{ url_for('image', tree_uuid=tree_uuid) }}" role="button">Download screenshot</a>
@ -101,6 +101,9 @@
<li> <li>
<a href="#screenshotModal" data-toggle="modal" data-target="#screenshotModal" role="button">Show screenshot</a> <a href="#screenshotModal" data-toggle="modal" data-target="#screenshotModal" role="button">Show screenshot</a>
</li> </li>
<li>
<a href="#/" role="button" onclick="MarkAsLegitimate('{{ tree_uuid }}');">Mark capture as legitimate</a>
</li>
{% if enable_mail_notification %} {% if enable_mail_notification %}
<li> <li>
<a href="#emailModal" data-toggle="modal" data-target="#emailModal" role="button">Notify by mail</a> <a href="#emailModal" data-toggle="modal" data-target="#emailModal" role="button">Notify by mail</a>