Skip to content

Commit b1bcd7d

Browse files
committed
feat: add parsed APK package info panel in findings view
Extract package metadata (package id/name/version/version code/sdk fields) from APK findings payloads, show it in a dedicated info bar, and remove metadata rows from the main findings table. Made-with: Cursor
1 parent c627de4 commit b1bcd7d

1 file changed

Lines changed: 102 additions & 0 deletions

File tree

  • internal/modules/gobot/ui

internal/modules/gobot/ui/app.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4422,6 +4422,75 @@ async function loadReconUnifiedTable(scanId, allFiles, containerId, scanRecord)
44224422

44234423
allRows = allRows.map(rowToGrid);
44244424

4425+
const extractApkPackageInfo = (rows) => {
4426+
const info = {};
4427+
const consumed = new Set();
4428+
const aliases = {
4429+
package_name: 'package_name',
4430+
package: 'package_name',
4431+
packageid: 'package_name',
4432+
package_id: 'package_name',
4433+
applicationid: 'package_name',
4434+
application_id: 'package_name',
4435+
appid: 'package_name',
4436+
app_name: 'app_name',
4437+
appname: 'app_name',
4438+
name: 'app_name',
4439+
version: 'version',
4440+
version_name: 'version',
4441+
versionname: 'version',
4442+
version_code: 'version_code',
4443+
versioncode: 'version_code',
4444+
min_sdk: 'min_sdk',
4445+
minsdk: 'min_sdk',
4446+
target_sdk: 'target_sdk',
4447+
targetsdk: 'target_sdk',
4448+
compile_sdk: 'compile_sdk',
4449+
compilesdk: 'compile_sdk',
4450+
};
4451+
const takeKV = (k, v) => {
4452+
const key = String(k || '').trim().toLowerCase().replace(/[^a-z0-9_]/g, '');
4453+
const mapped = aliases[key];
4454+
if (!mapped) return;
4455+
const val = String(v ?? '').trim();
4456+
if (!val) return;
4457+
if (!info[mapped]) info[mapped] = val;
4458+
};
4459+
4460+
rows.forEach((r, idx) => {
4461+
const target = String(r.target || '');
4462+
const finding = String(r.finding || '').trim();
4463+
if (!/[{]/.test(finding) && !/(package|version|sdk|app_name|application_id)/i.test(`${target} ${finding}`)) return;
4464+
4465+
let consumedRow = false;
4466+
try {
4467+
const parsed = JSON.parse(finding);
4468+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
4469+
Object.entries(parsed).forEach(([k, v]) => takeKV(k, v));
4470+
consumedRow = Object.keys(parsed).length > 0;
4471+
}
4472+
} catch (_) {
4473+
// ignore
4474+
}
4475+
const kvs = finding.match(/"?([A-Za-z_][A-Za-z0-9_ ]*)"?\s*:\s*"?([^,"}]+)"?/g) || [];
4476+
kvs.forEach((frag) => {
4477+
const m = frag.match(/"?([A-Za-z_][A-Za-z0-9_ ]*)"?\s*:\s*"?([^,"}]+)"?/);
4478+
if (m) takeKV(m[1], m[2]);
4479+
});
4480+
if (kvs.length) consumedRow = true;
4481+
if (consumedRow) consumed.add(idx);
4482+
});
4483+
4484+
return { info, rows: rows.filter((_, idx) => !consumed.has(idx)) };
4485+
};
4486+
4487+
let apkPackageInfo = null;
4488+
if (isAPKScan) {
4489+
const extracted = extractApkPackageInfo(allRows);
4490+
allRows = extracted.rows;
4491+
apkPackageInfo = extracted.info;
4492+
}
4493+
44254494
const apkCategoryKey = (r) => {
44264495
const t = String(r.target || '').trim();
44274496
if (t && t !== '-' && t !== '—') return t;
@@ -4497,6 +4566,7 @@ async function loadReconUnifiedTable(scanId, allFiles, containerId, scanRecord)
44974566
<div id="recon-left-rail" style="display:flex;flex-direction:column;gap:6px;padding:8px;overflow-y:auto;overflow-x:hidden;max-height:780px;scrollbar-width:thin"></div>
44984567
</aside>
44994568
<section style="min-width:0">
4569+
<div id="recon-apk-meta" style="display:none;padding:10px 12px;border-bottom:1px solid var(--border);background:rgba(34,211,238,.06)"></div>
45004570
<div id="recon-filter-bar" style="display:grid;grid-template-columns:minmax(200px,1.5fr) 140px 140px minmax(180px,1fr) auto;gap:8px;padding:10px;border-bottom:1px solid var(--border);background:rgba(2,6,23,.5)">
45014571
<input id="recon-filter-host" type="search" placeholder="🔍 Filter by target URL..." style="padding:8px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:6px;color:var(--text-primary);font-size:12px"/>
45024572
<select id="recon-filter-severity" style="padding:8px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:6px;color:var(--text-primary);font-size:12px">
@@ -4550,11 +4620,43 @@ async function loadReconUnifiedTable(scanId, allFiles, containerId, scanRecord)
45504620
</div>`;
45514621

45524622
const tabsEl = root.querySelector('#recon-left-rail');
4623+
const apkMetaBar = root.querySelector('#recon-apk-meta');
45534624
const filterBar = root.querySelector('#recon-filter-bar');
45544625
const standardView = root.querySelector('#recon-standard-view');
45554626
const assetsView = root.querySelector('#recon-assets-view');
45564627
const assetsContent = root.querySelector('#recon-assets-content');
45574628

4629+
if (apkMetaBar) {
4630+
if (isAPKScan && apkPackageInfo) {
4631+
const ordered = [
4632+
['package_name', 'Package ID'],
4633+
['app_name', 'App Name'],
4634+
['version', 'Version'],
4635+
['version_code', 'Version Code'],
4636+
['min_sdk', 'Min SDK'],
4637+
['target_sdk', 'Target SDK'],
4638+
['compile_sdk', 'Compile SDK'],
4639+
].filter(([k]) => apkPackageInfo[k]);
4640+
if (ordered.length) {
4641+
apkMetaBar.style.display = 'flex';
4642+
apkMetaBar.style.flexWrap = 'wrap';
4643+
apkMetaBar.style.gap = '8px';
4644+
apkMetaBar.innerHTML = ordered.map(([k, label]) => (
4645+
`<div style="display:flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid rgba(34,211,238,.28);border-radius:8px;background:rgba(2,6,23,.45)">
4646+
<span style="font-size:11px;color:#67e8f9">${esc(label)}:</span>
4647+
<span style="font-size:11px;color:var(--text-primary);font-family:var(--font-mono,monospace)">${esc(apkPackageInfo[k])}</span>
4648+
</div>`
4649+
)).join('');
4650+
} else {
4651+
apkMetaBar.style.display = 'none';
4652+
apkMetaBar.innerHTML = '';
4653+
}
4654+
} else {
4655+
apkMetaBar.style.display = 'none';
4656+
apkMetaBar.innerHTML = '';
4657+
}
4658+
}
4659+
45584660
const modSelect = root.querySelector('#recon-filter-module');
45594661
if (modSelect) {
45604662
const usedModules = [...new Set(allRows.map(r => normalizeModuleKey(r.module)))]

0 commit comments

Comments
 (0)