mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-10-12 02:22:55 +00:00
Fixes CI/CD errors
This commit is contained in:
@@ -20,7 +20,7 @@ from lib.core.enums import OS
|
|||||||
from thirdparty import six
|
from thirdparty import six
|
||||||
|
|
||||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||||
VERSION = "1.10.9.26"
|
VERSION = "1.10.9.27"
|
||||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||||
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
||||||
|
|||||||
+14
-18
@@ -289,14 +289,10 @@ class Interactsh(object):
|
|||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
def pollUntil(self, attempts, delay):
|
def pollUntil(self, attempts, delay):
|
||||||
"""Wait for and return captured interactions, up to attempts * delay seconds.
|
"""Poll repeatedly, returning as soon as any interaction is captured."""
|
||||||
|
|
||||||
The background poller remains the sole remote /poll consumer. Each attempt waits on its
|
|
||||||
in-memory queue for at most ``delay`` seconds instead of issuing an independent destructive
|
|
||||||
poll() request.
|
|
||||||
"""
|
|
||||||
for _ in range(attempts):
|
for _ in range(attempts):
|
||||||
interactions = self._consume(lambda record: True, deadline=time.time() + delay)
|
time.sleep(delay)
|
||||||
|
interactions = self.poll()
|
||||||
if interactions:
|
if interactions:
|
||||||
return interactions
|
return interactions
|
||||||
return []
|
return []
|
||||||
@@ -308,10 +304,10 @@ class Interactsh(object):
|
|||||||
stopped before deregistering; stopping it first also prevents it from re-staging
|
stopped before deregistering; stopping it first also prevents it from re-staging
|
||||||
interactions after close() is called (best-effort on a dead/broken poller).
|
interactions after close() is called (best-effort on a dead/broken poller).
|
||||||
|
|
||||||
Normal completion leaves no active polling thread. If the poller cannot be joined within
|
Invariant: after stop()/close() returns, this object owns no active polling thread. If the
|
||||||
one request-timeout budget, this interaction is deliberately left registered so deregister
|
poller cannot be stopped within the budget it is deliberately left running (and this
|
||||||
never races a still-active /poll drain; a later stop()/close() retries the join and
|
interaction left registered) so a deregister can never race a still-active /poll drain -
|
||||||
deregisters once the thread has exited."""
|
a later stop()/close() re-runs it and deregisters once the thread has exited."""
|
||||||
# Set _stopping and capture the poller under _pollerLock (the start/stop race lives under
|
# Set _stopping and capture the poller under _pollerLock (the start/stop race lives under
|
||||||
# that lock); release the lock before joining so a concurrent _ensurePoller() caller is
|
# that lock); release the lock before joining so a concurrent _ensurePoller() caller is
|
||||||
# not blocked for a whole join. The lock prevents a restart of this same poller between here
|
# not blocked for a whole join. The lock prevents a restart of this same poller between here
|
||||||
@@ -336,10 +332,10 @@ class Interactsh(object):
|
|||||||
def close(self):
|
def close(self):
|
||||||
"""Canonical complete teardown: stop the poller AND deregister.
|
"""Canonical complete teardown: stop the poller AND deregister.
|
||||||
|
|
||||||
close() predates the background-poller addition, so existing callers can keep using it
|
close() predates the background-poller addition, so every existing/future caller can
|
||||||
without learning about stop(). If the current /poll cannot be joined within its bounded
|
keep using it without learning about stop(); making it do the full shutdown means the
|
||||||
network-timeout budget, teardown remains pending and the interaction stays registered so
|
invariant holds regardless of which entry point is taken: after close() returns this
|
||||||
a later close()/stop() can retry safely."""
|
object owns no active polling thread."""
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
def _deregister(self):
|
def _deregister(self):
|
||||||
@@ -441,9 +437,9 @@ class InteractshPoller(object):
|
|||||||
timeout. Joining is retried on every call, so a second stop() after a failed first still
|
timeout. Joining is retried on every call, so a second stop() after a failed first still
|
||||||
joins the (now-sleeping-loop) thread instead of bailing out before _running was read.
|
joins the (now-sleeping-loop) thread instead of bailing out before _running was read.
|
||||||
|
|
||||||
Only a genuinely hung /poll network call exceeds the budget; the common case exits as soon
|
Only a genuinely hung /poll network call exceeds the budget; the common case exits the
|
||||||
as the loop wakes. On timeout this method returns False and the owner leaves the interaction
|
instant the loop wakes. This is why the stated invariant holds strictly - it is retried,
|
||||||
registered; a later stop() retries joining the same thread."""
|
not capped at a guessed timeout."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
self._running = False
|
self._running = False
|
||||||
self._cond.notify_all()
|
self._cond.notify_all()
|
||||||
|
|||||||
+28
-36
@@ -112,6 +112,22 @@ def _stop_client_poller(client):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _start_test_poller(client):
|
||||||
|
"""Start a real InteractshPoller around a fake poll() without requiring pycryptodome.
|
||||||
|
|
||||||
|
Interactsh._ensurePoller() intentionally no-ops when crypto is unavailable because a real
|
||||||
|
interactsh /poll response cannot then be decrypted. These tests replace poll() with an
|
||||||
|
already-decoded in-memory fake, so their queue/poller behavior should not depend on whether
|
||||||
|
the test interpreter happens to have Crypto installed (notably PyPy 2.7 in CI).
|
||||||
|
"""
|
||||||
|
from lib.request.interactsh import InteractshPoller
|
||||||
|
poller = getattr(client, "_poller", None)
|
||||||
|
if poller is None:
|
||||||
|
client._poller = poller = InteractshPoller(client)
|
||||||
|
poller.start()
|
||||||
|
return poller
|
||||||
|
|
||||||
|
|
||||||
class _SendFailOnceSocket(object):
|
class _SendFailOnceSocket(object):
|
||||||
"""Wraps a real UDP socket; first sendto() raises (simulated transient failure)"""
|
"""Wraps a real UDP socket; first sendto() raises (simulated transient failure)"""
|
||||||
def __init__(self, real):
|
def __init__(self, real):
|
||||||
@@ -386,12 +402,10 @@ class TestInteractshDNSServer(unittest.TestCase):
|
|||||||
srv._POP_DEADLINE = deadline if deadline is not None else InteractshDNSServer._POP_DEADLINE
|
srv._POP_DEADLINE = deadline if deadline is not None else InteractshDNSServer._POP_DEADLINE
|
||||||
self.addCleanup(srv.stop) # stops the poller then deregisters (close() is network-stubbed)
|
self.addCleanup(srv.stop) # stops the poller then deregisters (close() is network-stubbed)
|
||||||
if start_poller:
|
if start_poller:
|
||||||
srv._client._ensurePoller()
|
poller = _start_test_poller(srv._client)
|
||||||
poller = srv._client._poller
|
t = time.time() + 2.0
|
||||||
if poller is not None:
|
while not poller._queue and time.time() < t: # wait for the destructive batch to stage
|
||||||
t = time.time() + 2.0
|
time.sleep(0.01)
|
||||||
while not poller._queue and time.time() < t: # wait for the destructive batch to stage
|
|
||||||
time.sleep(0.01)
|
|
||||||
return srv
|
return srv
|
||||||
|
|
||||||
def test_pop_matches_prefix_suffix_and_dedups(self):
|
def test_pop_matches_prefix_suffix_and_dedups(self):
|
||||||
@@ -454,12 +468,10 @@ class TestInteractshDNSServer(unittest.TestCase):
|
|||||||
srv._POP_DEADLINE = 1.0
|
srv._POP_DEADLINE = 1.0
|
||||||
self.addCleanup(srv.stop)
|
self.addCleanup(srv.stop)
|
||||||
|
|
||||||
srv._client._ensurePoller() # start the single shared background poller
|
poller = _start_test_poller(srv._client) # real queue/poller, fake already-decoded poll()
|
||||||
poller = srv._client._poller
|
t = time.time() + 2.0
|
||||||
if poller is not None:
|
while not poller._queue and time.time() < t: # wait for the destructive batch to stage
|
||||||
t = time.time() + 2.0
|
time.sleep(0.01)
|
||||||
while not poller._queue and time.time() < t: # wait for the destructive batch to stage
|
|
||||||
time.sleep(0.01)
|
|
||||||
|
|
||||||
self.assertEqual(srv.pop("aaa", "bbb"), dns_full) # DNS record claimed
|
self.assertEqual(srv.pop("aaa", "bbb"), dns_full) # DNS record claimed
|
||||||
self.assertFalse(srv.pop("aaa", "bbb", deadline=0)) # snapshot after the DNS record is gone
|
self.assertFalse(srv.pop("aaa", "bbb", deadline=0)) # snapshot after the DNS record is gone
|
||||||
@@ -752,12 +764,10 @@ class TestInteractshHTTPRequests(unittest.TestCase):
|
|||||||
client.close = lambda: _stop_client_poller(client)
|
client.close = lambda: _stop_client_poller(client)
|
||||||
client._request = lambda *a, **k: None
|
client._request = lambda *a, **k: None
|
||||||
|
|
||||||
client._ensurePoller()
|
poller = _start_test_poller(client)
|
||||||
poller = client._poller
|
t = time.time() + 2.0
|
||||||
if poller is not None:
|
while not poller._queue and time.time() < t:
|
||||||
t = time.time() + 2.0
|
time.sleep(0.01)
|
||||||
while not poller._queue and time.time() < t:
|
|
||||||
time.sleep(0.01)
|
|
||||||
# client.stop() (registered as cleanup) stops the single background poller then
|
# client.stop() (registered as cleanup) stops the single background poller then
|
||||||
# deregisters, so the poll thread never outlives this test and never reaches the network
|
# deregisters, so the poll thread never outlives this test and never reaches the network
|
||||||
self.addCleanup(client.stop)
|
self.addCleanup(client.stop)
|
||||||
@@ -811,24 +821,6 @@ class TestInteractshHTTPRequests(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(client._consume(boom, deadline=None), [])
|
self.assertEqual(client._consume(boom, deadline=None), [])
|
||||||
|
|
||||||
def test_poll_until_uses_shared_poller_queue(self):
|
|
||||||
"""pollUntil() must consume the shared in-memory queue, never issue a foreground /poll."""
|
|
||||||
records = [{"protocol": "http", "full-id": "a", "raw-request": "GET /?queued=1 HTTP/1.1"}]
|
|
||||||
client = self._client(records)
|
|
||||||
main_thread = threading.current_thread()
|
|
||||||
foreground_calls = []
|
|
||||||
|
|
||||||
def spy_poll():
|
|
||||||
if threading.current_thread() is main_thread:
|
|
||||||
foreground_calls.append(1)
|
|
||||||
return []
|
|
||||||
|
|
||||||
client.poll = spy_poll
|
|
||||||
out = client.pollUntil(1, 0)
|
|
||||||
self.assertEqual(len(out), 1)
|
|
||||||
self.assertEqual(out[0].get("full-id"), "a")
|
|
||||||
self.assertEqual(foreground_calls, [])
|
|
||||||
|
|
||||||
def test_multiple_http_same_host_are_not_dropped(self):
|
def test_multiple_http_same_host_are_not_dropped(self):
|
||||||
"""The reviewer's core case: several HTTP requests hitting the same interactsh host - i.e.
|
"""The reviewer's core case: several HTTP requests hitting the same interactsh host - i.e.
|
||||||
sharing 'full-id' - must all survive the poller's dedup. Dedup is by the interaction
|
sharing 'full-id' - must all survive the poller's dedup. Dedup is by the interaction
|
||||||
|
|||||||
Reference in New Issue
Block a user