Skip to content

Commit

Permalink
sfwebui: merge stopscan and stopscanmulti (smicallef#1212)
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoles authored Jun 28, 2021
1 parent 88c98f8 commit ad6ac1b
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 112 deletions.
11 changes: 2 additions & 9 deletions sfcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -932,15 +932,8 @@ def do_stop(self, line):
self.edprint("Invalid syntax.")
return

d = self.request(self.ownopts['cli.server_baseurl'] + "/stopscan?id=" + id)
if not d:
return

s = json.loads(d)
if s[0] == "SUCCESS":
self.dprint("Successfully requested scan to stop. This could take some minutes to complete.")
else:
self.dprint("Unable to stop scan: " + str(s[1]))
self.request(self.ownopts['cli.server_baseurl'] + f"/stopscan?id={id}")
self.dprint(f"Successfully requested scan {id} to stop. This could take some minutes to complete.")

# Search for data, alias to find
def do_search(self, line):
Expand Down
97 changes: 22 additions & 75 deletions sfwebui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1225,96 +1225,43 @@ def startscan(self, scanname, scantarget, modulelist, typelist, usecase):

startscan.exposed = True

def stopscanmulti(self, ids):
"""Stop a scan
Args:
ids (str): comma separated list of scan IDs
Note:
Unnecessary for now given that only one simultaneous scan is permitted
Returns:
str: stop scan status as JSON
Raises:
HTTPRedirect: redirect to home page
"""

dbh = SpiderFootDb(self.config)
error = list()

for id in ids.split(","):
scaninfo = dbh.scanInstanceGet(id)

if not scaninfo:
return self.error("Invalid scan ID.")

scanname = str(scaninfo[0])
scanstatus = scaninfo[5]

if scanstatus == "FINISHED":
error.append(f"Scan '{scanname}' is in a finished state. <a href='/scandelete?id={id}&confirm=1'>Maybe you want to delete it instead?</a>")
continue

if scanstatus == "ABORTED":
error.append(f"Scan '{scanname}' is already aborted.")
continue

dbh.scanInstanceSet(id, status="ABORT-REQUESTED")

raise cherrypy.HTTPRedirect(f"{self.docroot}/")

stopscanmulti.exposed = True

@cherrypy.expose
@cherrypy.tools.json_out()
def stopscan(self, id):
"""Stop a scan.
"""Stop a scan
Args:
id (str): scan ID
id (str): comma separated list of scan IDs
Returns:
str: stop scan status as JSON
Raises:
HTTPRedirect: redirect to home page
str: JSON response
"""
if not id:
return self.jsonify_error('404', "No scan specified")

dbh = SpiderFootDb(self.config)
scaninfo = dbh.scanInstanceGet(id)

if not scaninfo:
if cherrypy.request.headers.get('Accept') and 'application/json' in cherrypy.request.headers.get('Accept'):
cherrypy.response.headers['Content-Type'] = "application/json; charset=utf-8"
return json.dumps(["ERROR", "Invalid scan ID."]).encode('utf-8')

return self.error("Invalid scan ID.")

scanstatus = scaninfo[5]

if scanstatus == "ABORTED":
if cherrypy.request.headers.get('Accept') and 'application/json' in cherrypy.request.headers.get('Accept'):
cherrypy.response.headers['Content-Type'] = "application/json; charset=utf-8"
return json.dumps(["ERROR", "Scan already aborted."]).encode('utf-8')
ids = id.split(',')

return self.error("The scan is already aborted.")
for scan_id in ids:
res = dbh.scanInstanceGet(scan_id)
if not res:
return self.jsonify_error('404', f"Scan {id} does not exist")

if not scanstatus == "RUNNING":
if cherrypy.request.headers.get('Accept') and 'application/json' in cherrypy.request.headers.get('Accept'):
cherrypy.response.headers['Content-Type'] = "application/json; charset=utf-8"
return json.dumps(["ERROR", "Scan in an invalid state for stopping."]).encode('utf-8')
scan_status = res[5]

return self.error(f"The running scan is currently in the state '{scanstatus}', please try again later or restart SpiderFoot.")
if scan_status == "FINISHED":
return self.jsonify_error('400', f"Scan {id} has already finished.")

dbh.scanInstanceSet(id, status="ABORT-REQUESTED")
if scan_status == "ABORTED":
return self.jsonify_error('400', f"Scan {id} has already aborted.")

if cherrypy.request.headers.get('Accept') and 'application/json' in cherrypy.request.headers.get('Accept'):
cherrypy.response.headers['Content-Type'] = "application/json; charset=utf-8"
return json.dumps(["SUCCESS", ""]).encode('utf-8')
if scan_status != "RUNNING":
return self.jsonify_error('400', f"The running scan is currently in the state '{scan_status}', please try again later or restart SpiderFoot.")

raise cherrypy.HTTPRedirect(f"{self.docroot}/")
for scan_id in ids:
dbh.scanInstanceSet(scan_id, status="ABORT-REQUESTED")

stopscan.exposed = True
return b""

#
# DATA PROVIDERS
Expand Down
15 changes: 13 additions & 2 deletions static/js/spiderfoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,19 @@ sf.deleteScan = function(scan_id) {
url: "/scandelete?id=" + scan_id
});
req.done(alertify.success('Scan ' + scan_id + ' deleted'));
req.fail(function (hr, status) {
alertify.error("Error: " + status);
req.fail(function (hr, textStatus, errorThrown) {
alertify.error("Error: " + hr.responseText);
});
};

sf.stopScan = function(scan_id) {
var req = $.ajax({
type: "GET",
url: "/stopscan?id=" + scan_id
});
req.done(alertify.success('Scan ' + scan_id + ' aborted'));
req.fail(function (hr, textStatus, errorThrown) {
alertify.error("Error: " + hr.responseText);
});
};

Expand Down
25 changes: 20 additions & 5 deletions static/js/spiderfoot.scanlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,33 @@
return ids;
}

function stopScan(id) {
alertify.confirm("Are you sure you wish to stop this scan?",
function(){
sf.stopScan(id);
reload();
}).set({title:"Stop scan?"});
}

function stopSelected() {
ids = getSelected();

if (ids != false) {
sf.log("Stopping scans: " + ids.join(','));
window.location.href = docroot + '/stopscanmulti?ids=' + ids.join(',');
if (!ids) {
alertify.message("Could not stop scans. No scans selected.");
return;
}

alertify.confirm("Are you sure you wish to stop these " + ids.length + " scans?<br/><br/>" + ids.join("<br/>"),
function(){
sf.stopScan(ids.join(','));
reload();
}).set({title:"Stop scans?"});
}

function deleteScan(id) {
alertify.confirm("Are you sure you wish to delete this scan?",
function(){
sf.deleteScan(id);
reload();
}).set({title:"Delete scan?"});
}

Expand All @@ -69,6 +83,7 @@
alertify.confirm("Are you sure you wish to delete these " + ids.length + " scans?<br/><br/>" + ids.join("<br/>"),
function(){
sf.deleteScan(ids.join(','));
reload();
}).set({title:"Delete scans?"});
}

Expand Down Expand Up @@ -204,7 +219,7 @@
table += "<td class='text-center'>" + data[i][7] + "</td>";
table += "<td class='text-center'>";
if (data[i][6] == "RUNNING" || data[i][6] == "STARTING" || data[i][6] == "STARTED" || data[i][6] == "INITIALIZING") {
table += "<a rel='tooltip' title='Stop Scan' href=" + docroot + "/stopscan?id=" + data[i][0] +"><i class='glyphicon glyphicon-stop text-muted'></i></a>";
table += "<a rel='tooltip' title='Stop Scan' href='javascript:stopScan(\"" + data[i][0] + "\");'><i class='glyphicon glyphicon-stop text-muted'></i></a>";
} else {
table += "<a rel='tooltip' title='Delete Scan' href='javascript:deleteScan(\"" + data[i][0] + "\");'><i class='glyphicon glyphicon-trash text-muted'></i></a>";
table += "&nbsp;&nbsp;<a rel='tooltip' title='Re-run Scan' href=" + docroot + "/rerunscan?id=" + data[i][0] + "><i class='glyphicon glyphicon-repeat text-muted'></i></a>";
Expand Down
12 changes: 4 additions & 8 deletions test/integration/test_sfwebui.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def test_optsraw(self):
def test_scandelete_invalid_scan_id_returns_404(self):
self.getPage("/scandelete?id=doesnotexist")
self.assertStatus('404 Not Found')
self.assertInBody('Scan doesnotexist does not exist')

@unittest.skip("todo")
def test_savesettings(self):
Expand Down Expand Up @@ -220,15 +221,10 @@ def test_startscan(self):
self.assertStatus('200 OK')
self.assertInBody('Invalid target type. Could not recognize it as a target SpiderFoot supports.')

def test_stopscanmulti(self):
self.getPage("/stopscanmulti?ids=doesnotexist")
self.assertStatus('200 OK')
self.assertInBody('Invalid scan ID.')

def test_stopscan(self):
def test_stopscan_invalid_scan_id_returns_404(self):
self.getPage("/stopscan?id=doesnotexist")
self.assertStatus('200 OK')
self.assertInBody('Invalid scan ID.')
self.assertStatus('404 Not Found')
self.assertInBody('Scan doesnotexist does not exist')

def test_scanlog_invalid_scan_returns_200(self):
self.getPage("/scanlog?id=doesnotexist")
Expand Down
16 changes: 3 additions & 13 deletions test/unit/test_spiderfootwebui.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,26 +344,16 @@ def test_start_scan(self):
"""
self.assertEqual('TBD', 'TBD')

def test_stopscanmulti(self):
"""
Test stopscanmulti(self, ids)
"""
opts = self.default_options
opts['__modules__'] = dict()
sfwebui = SpiderFootWebUi(self.web_default_options, opts)
stop_scan = sfwebui.stopscanmulti("example scan id")
self.assertIsInstance(stop_scan, str)

@unittest.skip("todo")
def test_stopscan(self):
def test_stopscan_invalid_scanid_should_return_an_error(self):
"""
Test stopscan(self, id)
"""
opts = self.default_options
opts['__modules__'] = dict()
sfwebui = SpiderFootWebUi(self.web_default_options, opts)
stop_scan = sfwebui.stopscan("example scan id")
self.assertIsInstance(stop_scan, str)
self.assertIsInstance(stop_scan, dict)
self.assertEqual("Scan example scan id does not exist", stop_scan.get('error').get('message'))

def test_scanlog_should_return_bytes(self):
"""
Expand Down

0 comments on commit ad6ac1b

Please sign in to comment.