Skip to content

Commit 0257c68

Browse files
committed
fix: 优化响应头回退与重复识别
1 parent 41e47ab commit 0257c68

6 files changed

Lines changed: 56 additions & 15 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "stackprism",
33
"private": true,
4-
"version": "1.2.70",
4+
"version": "1.2.71",
55
"type": "module",
66
"description": "StackPrism 用于检测网页前端、后端、CDN、SaaS、广告营销、统计、登录、支付、网站程序和主题模板线索。",
77
"scripts": {

public/rules/page/languages.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@
6262
"name": "FreeMarker",
6363
"kind": "后端模板语言",
6464
"confidence": "",
65-
"patterns": ["\\.ftl(?:\\?|#|$)", "freemarker", "FreeMarker template error", "org\\.apache\\.freemarker"]
65+
"patterns": [
66+
"\\.ftl(?:\\?|#|$)",
67+
"(?:^|/)pay/ftl(?:/|[?#\\s\"'<>]|$)",
68+
"freemarker",
69+
"FreeMarker template error",
70+
"org\\.apache\\.freemarker"
71+
]
6672
},
6773
{
6874
"name": "Java Servlet",

src/background/detection.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { augmentPageWithWordPressThemeStyles } from './wordpress'
22
import { buildPopupCacheRecord, cleanPageDetectionRecord } from './popup-cache'
3-
import { fetchMainHeadersFallback } from './headers'
3+
import { fetchMainHeadersFallback, mergeHeaderRecords } from './headers'
44
import { clearBadge, clearTabSession, getTabData, getTabSnapshot, updateBadgeForTab, writeTabData } from './tab-store'
55
import { buildEffectivePageRules, loadDetectorSettings, loadTechRules } from './detector-settings'
66
import { scheduleBundleLicenseDetection } from './bundle-license'
@@ -24,7 +24,7 @@ const needsMainHeadersFallback = (record: any, currentUrl: string): boolean => {
2424
const recordUrl = normalizePageUrl(record.url)
2525
const tabUrl = normalizePageUrl(currentUrl)
2626
if (recordUrl && tabUrl && recordUrl !== tabUrl) return true
27-
return !Number(record.headerCount || 0) && !(record.technologies || []).length
27+
return Number(record.headerCount || 0) <= 1 && !Object.keys(record.headers || {}).length && !(record.technologies || []).length
2828
}
2929

3030
const headerRecordMatchesUrl = (record: any, currentUrl: string): boolean => {
@@ -33,6 +33,22 @@ const headerRecordMatchesUrl = (record: any, currentUrl: string): boolean => {
3333
return Boolean(recordUrl && tabUrl && recordUrl === tabUrl)
3434
}
3535

36+
const headerRecordSharesPagePath = (record: any, currentUrl: string): boolean => {
37+
try {
38+
const recordUrl = new URL(String(record?.url || ''))
39+
const tabUrl = new URL(String(currentUrl || ''))
40+
return recordUrl.origin === tabUrl.origin && recordUrl.pathname === tabUrl.pathname
41+
} catch {
42+
return false
43+
}
44+
}
45+
46+
const hasUsefulHeaderRecord = (record: any): boolean =>
47+
Boolean(record && (Number(record.headerCount || 0) > 1 || Object.keys(record.headers || {}).length || (record.technologies || []).length))
48+
49+
const shouldPreserveMainHeaderRecord = (record: any, currentUrl: string): boolean =>
50+
headerRecordMatchesUrl(record, currentUrl) || (headerRecordSharesPagePath(record, currentUrl) && hasUsefulHeaderRecord(record))
51+
3652
export const saveTabDataAndBadge = async (tabId: number, data: any, settings: any) => {
3753
const tab = await getTabSnapshot(tabId)
3854
if (!isDetectablePageUrl(tab.url)) {
@@ -102,8 +118,13 @@ export const runActivePageDetection = async (tabId: number) => {
102118

103119
if (needsMainHeadersFallback(data.main, (page as any).url || tab.url)) {
104120
const fallback = await fetchMainHeadersFallback((page as any).url || '', rules.headers || {}, settings)
105-
if (fallback) data.main = fallback
106-
else if (data.main && !headerRecordMatchesUrl(data.main, (page as any).url || tab.url)) delete data.main
121+
if (fallback) {
122+
data.main = shouldPreserveMainHeaderRecord(data.main, (page as any).url || tab.url)
123+
? mergeHeaderRecords(data.main, fallback)
124+
: fallback
125+
} else if (data.main && !shouldPreserveMainHeaderRecord(data.main, (page as any).url || tab.url)) {
126+
delete data.main
127+
}
107128
}
108129

109130
data.updatedAt = Date.now()

src/background/headers.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ const normalizeHeaders = (responseHeaders: any[]) => {
3838
return map
3939
}
4040

41+
const collectFetchResponseHeaders = (response: Response) => {
42+
const responseHeaders: Array<{ name: string; value: string }> = []
43+
response.headers.forEach((value, name) => responseHeaders.push({ name, value }))
44+
return responseHeaders
45+
}
46+
4147
const pickHeaders = (headers: Record<string, string>, interestingNames: string[]) => {
4248
const picked: Record<string, string> = {}
4349
for (const name of interestingNames) {
@@ -129,14 +135,12 @@ export const fetchMainHeadersFallback = async (url: string, headerRules: any, se
129135
if (!url || !/^https?:/i.test(url)) return null
130136
try {
131137
let method = 'HEAD'
132-
let response = await fetch(url, { method, credentials: 'omit', cache: 'no-store', redirect: 'follow' })
133-
let responseHeaders: Array<{ name: string; value: string }> = []
134-
response.headers.forEach((value, name) => responseHeaders.push({ name, value }))
135-
if ((!response.ok && response.status !== 405 && response.status !== 0) || !responseHeaders.length) {
138+
let response = await fetch(url, { method, credentials: 'include', cache: 'no-store', redirect: 'follow' })
139+
let responseHeaders = collectFetchResponseHeaders(response)
140+
if ((!response.ok && response.status !== 0) || responseHeaders.length <= 1) {
136141
method = 'GET'
137-
response = await fetch(url, { method: 'GET', credentials: 'omit', cache: 'no-store', redirect: 'follow' })
138-
responseHeaders = []
139-
response.headers.forEach((value, name) => responseHeaders.push({ name, value }))
142+
response = await fetch(url, { method: 'GET', credentials: 'include', cache: 'no-store', redirect: 'follow' })
143+
responseHeaders = collectFetchResponseHeaders(response)
140144
}
141145
if (!responseHeaders.length) return null
142146
return buildHeaderRecord(

src/background/merge.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ export const isFrontendFallback = (item: any) => item?.category === '前端库'
5353
const frontendTechnologyCategories = new Set(['前端库', '前端框架', 'UI / CSS 框架'])
5454

5555
const frontendAliasTechnologies: Record<string, { category: string; name: string }> = {
56+
angular: { category: '前端框架', name: 'Angular' },
5657
jquerycompat: { category: '前端库', name: 'jQuery' },
57-
twitterbootstrap: { category: 'UI / CSS 框架', name: 'Bootstrap' }
58+
preact: { category: '前端框架', name: 'Preact' },
59+
react: { category: '前端框架', name: 'React' },
60+
svelte: { category: '前端框架', name: 'Svelte' },
61+
twitterbootstrap: { category: 'UI / CSS 框架', name: 'Bootstrap' },
62+
vue: { category: '前端框架', name: 'Vue' }
5863
}
5964

6065
export const canonicalizeFrontendAliasTechnologies = (items: any[]) => {

src/injected/page-detector.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,13 @@ const detectPageTechnologies = (ruleConfig: Record<string, unknown> = {}) => {
367367
return []
368368
}
369369
const aliases = {
370+
angular: { category: '前端框架', name: 'Angular' },
370371
jquerycompat: { category: '前端库', name: 'jQuery' },
371-
twitterbootstrap: { category: 'UI / CSS 框架', name: 'Bootstrap' }
372+
preact: { category: '前端框架', name: 'Preact' },
373+
react: { category: '前端框架', name: 'React' },
374+
svelte: { category: '前端框架', name: 'Svelte' },
375+
twitterbootstrap: { category: 'UI / CSS 框架', name: 'Bootstrap' },
376+
vue: { category: '前端框架', name: 'Vue' }
372377
}
373378
const frontendCategories = new Set(['前端库', '前端框架', 'UI / CSS 框架'])
374379
return items.map(item => {

0 commit comments

Comments
 (0)