Skip to content

Commit a2d4fc5

Browse files
committed
fix: 收紧误判规则并补充聚合登录识别
1 parent ed0c041 commit a2d4fc5

9 files changed

Lines changed: 168 additions & 13 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.63",
4+
"version": "1.2.64",
55
"type": "module",
66
"description": "StackPrism 用于检测网页前端、后端、CDN、SaaS、广告营销、统计、登录、支付、网站程序和主题模板线索。",
77
"scripts": {

public/rules/page/data-infra-assets.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,11 @@
345345
"name": "Apache NiFi",
346346
"kind": "数据流处理",
347347
"resourceHints": ["nifi"],
348-
"patterns": ["(?:^|/)nifi/(?:assets|css|js|images)(?:/|[?#]|$)", "nifi[^\\s\"'<>]*\\.(?:js|css|svg|png)(?:\\?|$)"]
348+
"patterns": [
349+
"(?:^|/)nifi/(?:assets|css|js|images)(?:/|[?#]|$)",
350+
"(?:^|/)apache[-_.]?nifi[^\\s\"'<>/]*\\.(?:js|css|svg|png)(?:[?#]|$)",
351+
"(?:^|/)nifi[-_.][^\\s\"'<>/]*\\.(?:js|css|svg|png)(?:[?#]|$)"
352+
]
349353
},
350354
{
351355
"name": "Apache Flink Dashboard",

public/rules/page/third-party-logins.json

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,83 @@
2727
{
2828
"name": "微博登录",
2929
"patterns": ["api\\.weibo\\.com/oauth2/authorize", "WB2\\.anyWhere", "SinaWeibo", "微博登录", "weibo login"]
30+
},
31+
{
32+
"name": "抖音登录",
33+
"patterns": ["open\\.douyin\\.com/platform/oauth/connect", "douyin\\.com/[^\\s\"'<>]*(?:oauth|authorize|login)", "抖音登录"]
34+
},
35+
{
36+
"name": "哔哩哔哩登录",
37+
"patterns": ["passport\\.bilibili\\.com", "bilibili\\.com/[^\\s\"'<>]*(?:oauth|authorize|login)", "哔哩哔哩登录", "Bilibili登录"]
38+
}
39+
]
40+
},
41+
{
42+
"defaults": {
43+
"kind": "聚合登录图标",
44+
"confidence": "",
45+
"resourceOnly": true
46+
},
47+
"rules": [
48+
{
49+
"name": "QQ 登录",
50+
"patterns": ["(?:^|/)assets/icon/qq\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
51+
},
52+
{
53+
"name": "微信登录",
54+
"patterns": ["(?:^|/)assets/icon/(?:wx|wechat|weixin)\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
55+
},
56+
{
57+
"name": "微博登录",
58+
"patterns": ["(?:^|/)assets/icon/(?:sina|weibo)\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
59+
},
60+
{
61+
"name": "支付宝登录",
62+
"patterns": ["(?:^|/)assets/icon/alipay\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
63+
},
64+
{
65+
"name": "百度帐号登录",
66+
"patterns": ["(?:^|/)assets/icon/baidu\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
67+
},
68+
{
69+
"name": "华为帐号登录",
70+
"patterns": ["(?:^|/)assets/icon/huawei\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
71+
},
72+
{
73+
"name": "小米帐号登录",
74+
"patterns": ["(?:^|/)assets/icon/xiaomi\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
75+
},
76+
{
77+
"name": "抖音登录",
78+
"patterns": ["(?:^|/)assets/icon/douyin\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
79+
},
80+
{
81+
"name": "哔哩哔哩登录",
82+
"patterns": ["(?:^|/)assets/icon/bilibili\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
83+
},
84+
{
85+
"name": "钉钉登录",
86+
"patterns": ["(?:^|/)assets/icon/dingtalk\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
87+
},
88+
{
89+
"name": "飞书 / Lark 登录",
90+
"patterns": ["(?:^|/)assets/icon/(?:feishu|lark)\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
91+
},
92+
{
93+
"name": "GitHub 登录",
94+
"patterns": ["(?:^|/)assets/icon/github\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
95+
},
96+
{
97+
"name": "Gitee 登录",
98+
"patterns": ["(?:^|/)assets/icon/gitee\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
99+
},
100+
{
101+
"name": "Google 登录",
102+
"patterns": ["(?:^|/)assets/icon/google\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
103+
},
104+
{
105+
"name": "Microsoft 登录",
106+
"patterns": ["(?:^|/)assets/icon/(?:microsoft|ms)\\.(?:png|svg|webp)(?:[?#]|[\"'<>\\s]|$)"]
30107
}
31108
]
32109
},

public/rules/page/ui-frameworks.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,10 @@
174174
},
175175
{
176176
"name": "Layui",
177-
"patterns": ["layui"],
178-
"classPrefixes": ["layui-"],
177+
"patterns": [
178+
"(?:^|/)layui(?:\\.all)?(?:\\.min)?\\.(?:js|css)(?:[?#]|[\"'<>\\s]|$)",
179+
"(?:^|/)layui/(?:layui|css/layui)[^\\s\"'<>]*\\.(?:js|css)(?:[?#]|[\"'<>\\s]|$)"
180+
],
179181
"classNames": ["layui-btn", "layui-form"]
180182
}
181183
]

public/rules/page/website-programs-extra.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,17 @@
241241
"matchType": "regex",
242242
"patterns": ["spring-plus\\.net", "Pu!mdHd"],
243243
"matchIn": ["url", "html"]
244+
},
245+
{
246+
"name": "彩虹聚合登录",
247+
"kind": "聚合登录系统",
248+
"url": "https://u.cccyun.cc",
249+
"matchType": "regex",
250+
"patterns": [
251+
"彩虹聚合登录",
252+
"(?=[\\s\\S]*(?:聚合登录\\s*-\\s*接口测试|/user/test\\.php(?:[?#\\s\"'<>]|$)))(?=[\\s\\S]*(?:name=[\"']alipayment[\"']|submitLogin\\s*\\(|ajax\\.php\\?act=test))"
253+
],
254+
"matchIn": ["html"]
244255
}
245256
]
246257
},

public/tech-links.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,8 @@
11271127
"QQ 登录": "https://connect.qq.com",
11281128
"微信登录": "https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html",
11291129
"微博登录": "https://open.weibo.com/wiki/Connect/login",
1130+
"抖音登录": "https://developer.open-douyin.com",
1131+
"哔哩哔哩登录": "https://openhome.bilibili.com",
11301132
"支付宝登录": "https://opendocs.alipay.com/open/289/105656",
11311133
"钉钉登录": "https://open.dingtalk.com",
11321134
"飞书 / Lark 登录": "https://open.feishu.cn",
@@ -1156,6 +1158,7 @@
11561158
"CAS 单点登录": "https://apereo.github.io/cas",
11571159
"SAML 登录": "https://en.wikipedia.org/wiki/SAML_2.0",
11581160
"OpenID Connect / OAuth2": "https://openid.net/developers/how-connect-works",
1161+
"彩虹聚合登录": "https://u.cccyun.cc",
11591162
"支付宝支付": "https://open.alipay.com",
11601163
"微信支付": "https://pay.weixin.qq.com",
11611164
"QQ 钱包": "https://qpay.qq.com",

src/background/bundle-license.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { matchesCompiledRulePatterns, matchesRuleTextHints } from './rule-matche
66
import { isDetectablePageUrl } from '@/utils/page-support'
77
import { cleanTechnologyUrl } from '@/utils/url'
88

9-
const BUNDLE_LICENSE_SCHEMA_VERSION = 3
9+
const BUNDLE_LICENSE_SCHEMA_VERSION = 4
1010
const BUNDLE_LICENSE_SOURCE = 'JS 版权注释'
1111
const MAX_CANDIDATE_SCRIPTS = 5
1212
const MAX_FETCH_BYTES = 384 * 1024
@@ -143,6 +143,32 @@ const collectCandidateScripts = (data: any, tabUrl: string): string[] => {
143143

144144
const buildBundleSignature = (scripts: string[]): string => scripts.join('\n')
145145

146+
const comparablePageUrl = (value: unknown): string => {
147+
try {
148+
const url = new URL(String(value || ''))
149+
url.hash = ''
150+
return url.href
151+
} catch {
152+
return ''
153+
}
154+
}
155+
156+
const getBundlePageIdentity = (data: any, tab: any): { url: string; title: string } => {
157+
const tabUrl = String(tab?.url || '')
158+
const pageUrl = String(data?.page?.url || '')
159+
const pageMatchesTab = pageUrl && comparablePageUrl(pageUrl) === comparablePageUrl(tabUrl)
160+
if (pageMatchesTab) {
161+
return {
162+
url: pageUrl,
163+
title: String(data?.page?.title || tab?.title || '')
164+
}
165+
}
166+
return {
167+
url: tabUrl,
168+
title: String(tab?.title || '')
169+
}
170+
}
171+
146172
const readLimitedResponseText = async (response: Response, maxBytes: number): Promise<string> => {
147173
if (!response.body) {
148174
return (await response.text()).slice(0, maxBytes)
@@ -378,12 +404,13 @@ export const runBundleLicenseDetection = async (tabId: number): Promise<void> =>
378404
}
379405

380406
const technologies = detectTechnologiesFromLicenseText(observations, pageRules.bundleLicenseLibraries || [])
407+
const pageIdentity = getBundlePageIdentity(data, tab)
381408

382409
data.bundle = {
383410
schemaVersion: BUNDLE_LICENSE_SCHEMA_VERSION,
384411
signature,
385-
url: tab.url,
386-
title: tab.title,
412+
url: pageIdentity.url,
413+
title: pageIdentity.title,
387414
updatedAt: Date.now(),
388415
scripts: observations.map(observation => ({
389416
url: observation.url,

src/background/merge.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,20 @@ export const shortHeaderUrl = (raw: unknown): string => {
2727
}
2828
}
2929

30-
export const normalizeDynamicFallbackTechName = (name: unknown): string =>
31-
String(name || '')
30+
export const normalizeDynamicFallbackTechName = (name: unknown): string => {
31+
const normalized = String(name || '')
3232
.toLowerCase()
3333
.replace(/^:\s*/, '')
3434
.replace(/(?:\.js|js)$/i, '')
3535
.replace(/(?:[._-]pkgd)$/i, '')
3636
.replace(/[^a-z0-9-]+/g, '')
3737

38+
const aliases: Record<string, string> = {
39+
slickcarousel: 'slick'
40+
}
41+
return aliases[normalized] || normalized
42+
}
43+
3844
export const isFrontendFallback = (item: any) => item?.category === '前端库' && /^:/i.test(String(item?.name || '').trim())
3945

4046
const isWordPressThemeDirectoryFallbackEvidence = (evidenceText: string) =>

src/injected/page-detector.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,12 +342,16 @@ const detectPageTechnologies = (ruleConfig: Record<string, unknown> = {}) => {
342342
}
343343

344344
function normalizeFallbackTechName(name) {
345-
return String(name || '')
345+
const normalized = String(name || '')
346346
.toLowerCase()
347347
.replace(/^:\s*/, '')
348348
.replace(/(?:\.js|js)$/i, '')
349349
.replace(/(?:[._-]pkgd)$/i, '')
350350
.replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '')
351+
const aliases = {
352+
slickcarousel: 'slick'
353+
}
354+
return aliases[normalized] || normalized
351355
}
352356

353357
function suppressFrontendFallbackDuplicates(items) {
@@ -1159,18 +1163,39 @@ ${html}`
11591163

11601164
function scoreTailwind(classes) {
11611165
const tokens = Object.keys(classes)
1162-
let score = 0
1166+
let utilityScore = 0
1167+
let specificScore = 0
1168+
let bootstrapScore = 0
1169+
let distinctUtilityCount = 0
11631170
let count = 0
11641171
const TAILWIND_PATTERN =
11651172
/^(?:sm|md|lg|xl|2xl):|^-?(?:m|p|mt|mr|mb|ml|mx|my|pt|pr|pb|pl|px|py)-|^(?:text|bg|border|ring|shadow|rounded|grid|flex|items|justify|gap|space|w|h|min-w|max-w|min-h|max-h)-|^(?:hover|focus|active|disabled|dark):|\[[^\]]+\]/
1173+
const TAILWIND_SPECIFIC_PATTERN =
1174+
/^(?:sm|md|lg|xl|2xl|hover|focus|active|disabled|dark):|^\[[^\]]+\]$|^(?:text|bg|border|ring|from|to|via)-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950)$|^(?:grid-cols|grid-rows|gap|space-x|space-y)-\d+$|^(?:w|h|min-w|max-w|min-h|max-h)-(?:screen|full|fit|min|max|\d+\/\d+)$/
1175+
const BOOTSTRAP_PATTERN =
1176+
/^(?:container(?:-(?:fluid|sm|md|lg|xl|xxl))?|row|col(?:-\d+|-(?:sm|md|lg|xl|xxl)(?:-\d+)?)?|btn(?:-.+)?|navbar(?:-.+)?|card(?:-.+)?|dropdown(?:-.+)?|modal(?:-.+)?|form(?:-.+)?|input-group(?:-.+)?|table(?:-.+)?|alert(?:-.+)?|badge(?:-.+)?|d-(?:none|inline|inline-block|block|grid|table|flex|inline-flex)|justify-content-.+|align-items-.+|text-(?:center|start|end|left|right|muted|primary|secondary|success|danger|warning|info|light|dark|white|body|black-50|white-50)|(?:m|p)[tblrxy]?-(?:[0-5]|auto)|mdi(?:-.+)?)$/
11661177
for (const token of tokens) {
11671178
if (count++ >= 5000) break
1179+
if (BOOTSTRAP_PATTERN.test(token)) {
1180+
const c = classes[token]
1181+
bootstrapScore += c < 3 ? c : 3
1182+
}
11681183
if (TAILWIND_PATTERN.test(token)) {
11691184
const c = classes[token]
1170-
score += c < 3 ? c : 3
1185+
utilityScore += c < 3 ? c : 3
1186+
distinctUtilityCount += 1
1187+
if (TAILWIND_SPECIFIC_PATTERN.test(token)) {
1188+
specificScore += c < 3 ? c : 3
1189+
}
11711190
}
11721191
}
1173-
return score
1192+
if (specificScore < 3 && bootstrapScore >= 8) {
1193+
return 0
1194+
}
1195+
if (specificScore < 2 && (distinctUtilityCount < 14 || utilityScore < 24)) {
1196+
return 0
1197+
}
1198+
return utilityScore + specificScore * 4
11741199
}
11751200

11761201
function getMetaContent(name) {

0 commit comments

Comments
 (0)