Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/utils/hashdb.py
2989 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import hashlib
9
import os
10
import sqlite3
11
import threading
12
import time
13
14
from lib.core.common import getSafeExString
15
from lib.core.common import serializeObject
16
from lib.core.common import singleTimeWarnMessage
17
from lib.core.common import unserializeObject
18
from lib.core.compat import xrange
19
from lib.core.convert import getBytes
20
from lib.core.convert import getUnicode
21
from lib.core.data import logger
22
from lib.core.exception import SqlmapConnectionException
23
from lib.core.settings import HASHDB_END_TRANSACTION_RETRIES
24
from lib.core.settings import HASHDB_FLUSH_RETRIES
25
from lib.core.settings import HASHDB_FLUSH_THRESHOLD
26
from lib.core.settings import HASHDB_RETRIEVE_RETRIES
27
from lib.core.threads import getCurrentThreadData
28
from lib.core.threads import getCurrentThreadName
29
from thirdparty import six
30
31
class HashDB(object):
32
def __init__(self, filepath):
33
self.filepath = filepath
34
self._write_cache = {}
35
self._cache_lock = threading.Lock()
36
self._connections = []
37
38
def _get_cursor(self):
39
threadData = getCurrentThreadData()
40
41
if threadData.hashDBCursor is None:
42
try:
43
connection = sqlite3.connect(self.filepath, timeout=3, isolation_level=None)
44
self._connections.append(connection)
45
threadData.hashDBCursor = connection.cursor()
46
threadData.hashDBCursor.execute("CREATE TABLE IF NOT EXISTS storage (id INTEGER PRIMARY KEY, value TEXT)")
47
connection.commit()
48
except Exception as ex:
49
errMsg = "error occurred while opening a session "
50
errMsg += "file '%s' ('%s')" % (self.filepath, getSafeExString(ex))
51
raise SqlmapConnectionException(errMsg)
52
53
return threadData.hashDBCursor
54
55
def _set_cursor(self, cursor):
56
threadData = getCurrentThreadData()
57
threadData.hashDBCursor = cursor
58
59
cursor = property(_get_cursor, _set_cursor)
60
61
def close(self):
62
threadData = getCurrentThreadData()
63
try:
64
if threadData.hashDBCursor:
65
threadData.hashDBCursor.connection.commit()
66
threadData.hashDBCursor.close()
67
threadData.hashDBCursor.connection.close()
68
threadData.hashDBCursor = None
69
except:
70
pass
71
72
def closeAll(self):
73
for connection in self._connections:
74
try:
75
connection.commit()
76
connection.close()
77
except:
78
pass
79
80
@staticmethod
81
def hashKey(key):
82
key = getBytes(key if isinstance(key, six.text_type) else repr(key), errors="xmlcharrefreplace")
83
retVal = int(hashlib.md5(key).hexdigest(), 16) & 0x7fffffffffffffff # Reference: http://stackoverflow.com/a/4448400
84
return retVal
85
86
def retrieve(self, key, unserialize=False):
87
retVal = None
88
89
if key and (self._write_cache or os.path.isfile(self.filepath)):
90
hash_ = HashDB.hashKey(key)
91
retVal = self._write_cache.get(hash_)
92
if not retVal:
93
for _ in xrange(HASHDB_RETRIEVE_RETRIES):
94
try:
95
for row in self.cursor.execute("SELECT value FROM storage WHERE id=?", (hash_,)):
96
retVal = row[0]
97
except (sqlite3.OperationalError, sqlite3.DatabaseError) as ex:
98
if any(_ in getSafeExString(ex) for _ in ("locked", "no such table")):
99
warnMsg = "problem occurred while accessing session file '%s' ('%s')" % (self.filepath, getSafeExString(ex))
100
singleTimeWarnMessage(warnMsg)
101
elif "Could not decode" in getSafeExString(ex):
102
break
103
else:
104
errMsg = "error occurred while accessing session file '%s' ('%s'). " % (self.filepath, getSafeExString(ex))
105
errMsg += "If the problem persists please rerun with '--flush-session'"
106
raise SqlmapConnectionException(errMsg)
107
else:
108
break
109
110
time.sleep(1)
111
112
if retVal and unserialize:
113
try:
114
retVal = unserializeObject(retVal)
115
except:
116
retVal = None
117
warnMsg = "error occurred while unserializing value for session key '%s'. " % key
118
warnMsg += "If the problem persists please rerun with '--flush-session'"
119
logger.warning(warnMsg)
120
121
return retVal
122
123
def write(self, key, value, serialize=False):
124
if key:
125
hash_ = HashDB.hashKey(key)
126
self._cache_lock.acquire()
127
self._write_cache[hash_] = getUnicode(value) if not serialize else serializeObject(value)
128
self._cache_lock.release()
129
130
if getCurrentThreadName() in ('0', "MainThread"):
131
self.flush()
132
133
def flush(self, forced=False):
134
if not self._write_cache:
135
return
136
137
if not forced and len(self._write_cache) < HASHDB_FLUSH_THRESHOLD:
138
return
139
140
self._cache_lock.acquire()
141
_ = self._write_cache
142
self._write_cache = {}
143
self._cache_lock.release()
144
145
try:
146
self.beginTransaction()
147
for hash_, value in _.items():
148
retries = 0
149
while True:
150
try:
151
try:
152
self.cursor.execute("INSERT INTO storage VALUES (?, ?)", (hash_, value,))
153
except sqlite3.IntegrityError:
154
self.cursor.execute("UPDATE storage SET value=? WHERE id=?", (value, hash_,))
155
except (UnicodeError, OverflowError): # e.g. surrogates not allowed (Issue #3851)
156
break
157
except sqlite3.DatabaseError as ex:
158
if not os.path.exists(self.filepath):
159
debugMsg = "session file '%s' does not exist" % self.filepath
160
logger.debug(debugMsg)
161
break
162
163
if retries == 0:
164
warnMsg = "there has been a problem while writing to "
165
warnMsg += "the session file ('%s')" % getSafeExString(ex)
166
logger.warning(warnMsg)
167
168
if retries >= HASHDB_FLUSH_RETRIES:
169
return
170
else:
171
retries += 1
172
time.sleep(1)
173
else:
174
break
175
finally:
176
self.endTransaction()
177
178
def beginTransaction(self):
179
threadData = getCurrentThreadData()
180
if not threadData.inTransaction:
181
try:
182
self.cursor.execute("BEGIN TRANSACTION")
183
except:
184
try:
185
# Reference: http://stackoverflow.com/a/25245731
186
self.cursor.close()
187
except sqlite3.ProgrammingError:
188
pass
189
threadData.hashDBCursor = None
190
self.cursor.execute("BEGIN TRANSACTION")
191
finally:
192
threadData.inTransaction = True
193
194
def endTransaction(self):
195
threadData = getCurrentThreadData()
196
if threadData.inTransaction:
197
retries = 0
198
while retries < HASHDB_END_TRANSACTION_RETRIES:
199
try:
200
self.cursor.execute("END TRANSACTION")
201
threadData.inTransaction = False
202
except sqlite3.OperationalError:
203
pass
204
except sqlite3.ProgrammingError:
205
self.cursor = None
206
threadData.inTransaction = False
207
return
208
else:
209
return
210
211
retries += 1
212
time.sleep(1)
213
214
try:
215
self.cursor.execute("ROLLBACK TRANSACTION")
216
except sqlite3.OperationalError:
217
self.cursor.close()
218
self.cursor = None
219
finally:
220
threadData.inTransaction = False
221
222