mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-04-07 10:44:19 +03:00
This PR adds SORTABLE_HTML to dump options for adding sort links to the tables in HTML dumps.
This commit is contained in:
parent
04b293d44f
commit
27f6d7e6a5
|
@ -174,8 +174,8 @@ e050353f74c0baaf906ffca91dd04591645455ae363ae732a7a23f91ffe2ef1c lib/core/datat
|
|||
bdd1b5b3eb42cffdc1be78b8fe4e1bb2ec17cd86440a7aeb08fc599205089e94 lib/core/decorators.py
|
||||
9219f0bd659e4e22f4238ca67830adcb1e86041ce7fd3a8ae0e842f2593ae043 lib/core/defaults.py
|
||||
ec8d94fb704c0a40c88f5f283624cda025e2ea0e8b68722fe156c2b5676f53ac lib/core/dicts.py
|
||||
65fb5a2fc7b3bb502cc2db684370f213ab76bff875f3cf72ef2b9ace774efda9 lib/core/dump.py
|
||||
0e28c66ea9dfa1b721cfca63c364bdc139f53ebc8f9c57126b0af7dc6b433dcc lib/core/enums.py
|
||||
2070b406f123e4cc2b0015d125947c48b5f9afcb976ffaba9534841d30325310 lib/core/dump.py
|
||||
d653ec01dfa47ee93d2ffe53b1ab76b3a4fb649f517f9f6572a38186882e0255 lib/core/enums.py
|
||||
64bf6a5c2e456306a7b4f4c51f077412daf6c697fed232d8e23b77fd1a4c736e lib/core/exception.py
|
||||
93c256111dc753967169988e1289a0ea10ec77bfb8e2cbd1f6725e939bfbc235 lib/core/gui.py
|
||||
1d6e741e19e467650dce2ca84aa824d6df68ff74aedbe4afa8dbdb0193d94918 lib/core/__init__.py
|
||||
|
@ -188,7 +188,7 @@ c6a182f6b7d3b0ad6f0888ea2a4de4148f0770549038d7de8bc3267b4c6635f7 lib/core/readl
|
|||
63ae69713c6ea9abfa10e71dfab8f2dcf42432177a38d2c1e98785bf1468674c lib/core/replication.py
|
||||
5bad5bc7115051cef7b84efa73fbafbf5e1db46eef32a445056b56cda750b66f lib/core/revision.py
|
||||
0dcb52c9c76a4b0acf2e9038f7d8f08c14543cef3cf7032831c6c0a99376ad24 lib/core/session.py
|
||||
f04c8a49a6c7205949d54bed4226abf8ab97361ceb4e0325fc260456a0ad412f lib/core/settings.py
|
||||
fffc75cd873d5d75436e24a0121492e08a436846673ff43fffc3b2173162ff94 lib/core/settings.py
|
||||
a1e4f2860bffc73bbf2e5db293fa49dcb600ea35f950cda43dc953b3160ab3db lib/core/shell.py
|
||||
841716e87b90a3b598515910841f7cf8d33bb87c24a27fba1a80e36a831cbcd7 lib/core/subprocessng.py
|
||||
9731092f195e346716929323ea3c93247b23b9b92b0f32d3fd0acc3adf9876cc lib/core/target.py
|
||||
|
@ -476,8 +476,8 @@ b3d9d0644197ecb864e899c04ee9c7cd63891ecf2a0d3c333aad563eef735294 plugins/generi
|
|||
5a473c60853f54f1a4b14d79b8237f659278fe8a6b42e935ed573bf22b6d5b2c README.md
|
||||
8c4fd81d84598535643cf0ef1b2d350cd92977cb55287e23993b76eaa2215c30 sqlmapapi.py
|
||||
168309215af7dd5b0b71070e1770e72f1cbb29a3d8025143fb8aa0b88cd56b62 sqlmapapi.yaml
|
||||
4037f1c78180550c1896543581c0c2423e970086bae46f175397f2b4c54b7323 sqlmap.conf
|
||||
f84846b8493d809d697a75b3d13d904013bbb03e0edd82b724f4753801609057 sqlmap.py
|
||||
4e50d22751329b8be291c85436e42dfda80551c6d12eb63cad1342cde0783eac sqlmap.conf
|
||||
9f78d6f04525cf2d2978f210d40663df9757450669d9685bf43931e3b11059a8 sqlmap.py
|
||||
9d408612a6780f7f50a7f7887f923ff3f40be5bfa09a951c6dc273ded05b56c0 tamper/0eunion.py
|
||||
c1c2eaa7df016cc7786ccee0ae4f4f363b1dce139c61fb3e658937cb0d18fc54 tamper/apostrophemask.py
|
||||
19023093ab22aec3bce9523f28e8111e8f6125973e6d9c82adb60da056bdf617 tamper/apostrophenullencode.py
|
||||
|
|
|
@ -47,6 +47,8 @@ from lib.core.exception import SqlmapValueException
|
|||
from lib.core.replication import Replication
|
||||
from lib.core.settings import DUMP_FILE_BUFFER_SIZE
|
||||
from lib.core.settings import HTML_DUMP_CSS_STYLE
|
||||
from lib.core.settings import HTML_DUMP_CSS_SORTABLE_STYLE
|
||||
from lib.core.settings import HTML_DUMP_SORTABLE_JAVASCRIPT
|
||||
from lib.core.settings import IS_WIN
|
||||
from lib.core.settings import METADB_SUFFIX
|
||||
from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE
|
||||
|
@ -541,6 +543,9 @@ class Dump(object):
|
|||
dataToDumpFile(dumpFP, "<meta name=\"generator\" content=\"%s\" />\n" % VERSION_STRING)
|
||||
dataToDumpFile(dumpFP, "<title>%s</title>\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table)))
|
||||
dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE)
|
||||
if conf.dumpSortable:
|
||||
dataToDumpFile(dumpFP, HTML_DUMP_CSS_SORTABLE_STYLE)
|
||||
dataToDumpFile(dumpFP, HTML_DUMP_SORTABLE_JAVASCRIPT)
|
||||
dataToDumpFile(dumpFP, "\n</head>\n<body>\n<table>\n<thead>\n<tr>\n")
|
||||
|
||||
if count == 1:
|
||||
|
|
|
@ -229,6 +229,7 @@ class REGISTRY_OPERATION(object):
|
|||
class DUMP_FORMAT(object):
|
||||
CSV = "CSV"
|
||||
HTML = "HTML"
|
||||
SORTABLE_HTML = "SORTABLE_HTML"
|
||||
SQLITE = "SQLITE"
|
||||
|
||||
class HTTP_HEADER(object):
|
||||
|
|
|
@ -918,29 +918,163 @@ HTTP_CHUNKED_SPLIT_KEYWORDS = ("SELECT", "UPDATE", "INSERT", "FROM", "LOAD_FILE"
|
|||
|
||||
# CSS style used in HTML dump format
|
||||
HTML_DUMP_CSS_STYLE = """<style>
|
||||
table{
|
||||
margin:10;
|
||||
background-color:#FFFFFF;
|
||||
font-family:verdana;
|
||||
font-size:12px;
|
||||
align:center;
|
||||
table {
|
||||
margin: 10px;
|
||||
background: #fff;
|
||||
font: 12px verdana;
|
||||
text-align: center;
|
||||
}
|
||||
thead{
|
||||
font-weight:bold;
|
||||
background-color:#4F81BD;
|
||||
color:#FFFFFF;
|
||||
color: #fff;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #D3DFEE
|
||||
}
|
||||
td{
|
||||
font-size:12px;
|
||||
}
|
||||
th{
|
||||
font-size:12px;
|
||||
background-color: #D3DFEE;
|
||||
}
|
||||
</style>"""
|
||||
|
||||
HTML_DUMP_CSS_SORTABLE_STYLE = """
|
||||
<style>
|
||||
table thead th {
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
table thead th::after,
|
||||
table thead th::before {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
table thead th::after {
|
||||
margin-left: 3px;
|
||||
content: "▸";
|
||||
}
|
||||
|
||||
table thead th:hover::after,
|
||||
table thead th[aria-sort]::after {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
table thead th[aria-sort=descending]::after {
|
||||
content: "▾";
|
||||
}
|
||||
|
||||
table thead th[aria-sort=ascending]::after {
|
||||
content: "▴";
|
||||
}
|
||||
|
||||
table thead th.indicator-left::before {
|
||||
margin-right: 3px;
|
||||
content: "▸";
|
||||
}
|
||||
|
||||
table thead th.indicator-left[aria-sort=descending]::before {
|
||||
color: inherit;
|
||||
content: "▾";
|
||||
}
|
||||
|
||||
table thead th.indicator-left[aria-sort=ascending]::before {
|
||||
color: inherit;
|
||||
content: "▴";
|
||||
}
|
||||
</style>
|
||||
"""
|
||||
HTML_DUMP_SORTABLE_JAVASCRIPT = """<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
document.addEventListener('click', event => {
|
||||
try {
|
||||
const isAltSort = event.shiftKey || event.altKey;
|
||||
|
||||
// Find the clicked table header
|
||||
const findParentElement = (element, nodeName) =>
|
||||
element.nodeName === nodeName ? element : findParentElement(element.parentNode, nodeName);
|
||||
|
||||
const headerCell = findParentElement(event.target, 'TH');
|
||||
const headerRow = headerCell.parentNode;
|
||||
const thead = headerRow.parentNode;
|
||||
const table = thead.parentNode;
|
||||
|
||||
if (thead.nodeName !== 'THEAD') return;
|
||||
|
||||
// Reset sort indicators on other headers
|
||||
Array.from(headerRow.cells).forEach(cell => {
|
||||
if (cell !== headerCell) cell.removeAttribute('aria-sort');
|
||||
});
|
||||
|
||||
// Toggle sort direction
|
||||
const currentSort = headerCell.getAttribute('aria-sort');
|
||||
const isAscending = table.classList.contains('asc') && currentSort !== 'ascending';
|
||||
const sortDirection = (currentSort === 'descending' || isAscending) ? 'ascending' : 'descending';
|
||||
headerCell.setAttribute('aria-sort', sortDirection);
|
||||
|
||||
// Debounce sort operation
|
||||
if (table.dataset.timer) clearTimeout(Number(table.dataset.timer));
|
||||
|
||||
table.dataset.timer = setTimeout(() => {
|
||||
sortTable(table, isAltSort);
|
||||
}, 1).toString();
|
||||
} catch (error) {
|
||||
console.error('Sorting error:', error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function sortTable(table, useAltSort) {
|
||||
table.dispatchEvent(new CustomEvent('sort-start', { bubbles: true }));
|
||||
|
||||
const sortHeader = table.tHead.querySelector('th[aria-sort]');
|
||||
const headerRow = table.tHead.children[0];
|
||||
const isAscending = sortHeader.getAttribute('aria-sort') === 'ascending';
|
||||
const shouldPushEmpty = table.classList.contains('n-last');
|
||||
const sortColumnIndex = Number(sortHeader.dataset.sortCol ?? sortHeader.cellIndex);
|
||||
|
||||
const getCellValue = cell => {
|
||||
if (useAltSort) return cell.dataset.sortAlt;
|
||||
return cell.dataset.sort ?? cell.textContent;
|
||||
};
|
||||
|
||||
const compareRows = (row1, row2) => {
|
||||
const value1 = getCellValue(row1.cells[sortColumnIndex]);
|
||||
const value2 = getCellValue(row2.cells[sortColumnIndex]);
|
||||
|
||||
// Handle empty values
|
||||
if (shouldPushEmpty) {
|
||||
if (value1 === '' && value2 !== '') return -1;
|
||||
if (value2 === '' && value1 !== '') return 1;
|
||||
}
|
||||
|
||||
// Compare numerically if possible, otherwise use string comparison
|
||||
const numericDiff = Number(value1) - Number(value2);
|
||||
const comparison = isNaN(numericDiff) ?
|
||||
value1.localeCompare(value2, undefined, { numeric: true }) :
|
||||
numericDiff;
|
||||
|
||||
// Handle tiebreaker
|
||||
if (comparison === 0 && headerRow.cells[sortColumnIndex]?.dataset.sortTbr) {
|
||||
const tiebreakIndex = Number(headerRow.cells[sortColumnIndex].dataset.sortTbr);
|
||||
return compareRows(row1, row2, tiebreakIndex);
|
||||
}
|
||||
|
||||
return isAscending ? -comparison : comparison;
|
||||
};
|
||||
|
||||
// Sort each tbody
|
||||
Array.from(table.tBodies).forEach(tbody => {
|
||||
const rows = Array.from(tbody.rows);
|
||||
const sortedRows = rows.sort(compareRows);
|
||||
|
||||
const newTbody = tbody.cloneNode();
|
||||
newTbody.append(...sortedRows);
|
||||
tbody.replaceWith(newTbody);
|
||||
});
|
||||
|
||||
table.dispatchEvent(new CustomEvent('sort-end', { bubbles: true }));
|
||||
}
|
||||
</script>"""
|
||||
# Leaving (dirty) possibility to change values from here (e.g. `export SQLMAP__MAX_NUMBER_OF_THREADS=20`)
|
||||
for key, value in os.environ.items():
|
||||
if key.upper().startswith("%s_" % SQLMAP_ENVIRONMENT_PREFIX):
|
||||
|
|
|
@ -758,9 +758,10 @@ csvDel = ,
|
|||
dumpFile =
|
||||
|
||||
# Format of dumped data
|
||||
# Valid: CSV, HTML or SQLITE
|
||||
# Valid: CSV, HTML, SORTABLE_HTML or SQLITE
|
||||
dumpFormat = CSV
|
||||
|
||||
dumpSortable = False
|
||||
# Force character encoding used for data retrieval.
|
||||
encoding =
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user