基于Cssom的暗鏈檢測(cè)技術(shù)
原文合集地址如下,有需要的朋友可以關(guān)注
[本文地址](https://mp.weixin.qq.com/s/2n2QPkuChzTCezseMHIwMQ)
[合集地址](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzI5MjY4OTQ2Nw==&action=getalbum&album_id=2968591493596708865&scene=173&from_msgid=2247484203&from_itemidx=1&count=3&nolastread=1#wechat_redirect)
# 什么是暗鏈
大部分的開源代碼在實(shí)現(xiàn)暗鏈檢測(cè)的時(shí)候都是直接判斷頁面里面有沒有敏感詞,如果有,就認(rèn)為該鏈接為暗鏈。這種做法其實(shí)是有誤的。
違規(guī)鏈接應(yīng)該分為:外鏈、內(nèi)鏈、死鏈和暗鏈。而暗鏈除了違規(guī),還應(yīng)該具備“暗”這個(gè)看不見的特征。
## 暗鏈的特征
其實(shí)“暗鏈”就是看不見的網(wǎng)站鏈接,“暗鏈”在網(wǎng)站中的鏈接做得非常隱蔽,短時(shí)間內(nèi)不易被搜索引擎察覺。是做非法SEO的常用手段。
下面是一些特征
```html
<!-- 正常連接 -->
<a href="https://www.baidu.com">正常外鏈</a>
<!-- position位置類暗鏈 -->
<!-- position位置樣式,將元素的top、left位置設(shè)置成負(fù)數(shù),讓元素處于可視區(qū)外 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="position: absolute; top: -999px; left: -999px;">position暗鏈</a>
<!-- display 和 visibility 隱藏類暗鏈 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="display: none;">display為none使得鏈接不可見</a>
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="visibility: hidden;">display為hidden使得鏈接不可見</a>
<!-- 鏈接顏色和文字類暗鏈 -->
<!-- 鏈接顏色與背景色相同或相似,color采用十六進(jìn)制表達(dá)色彩 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="color: #ffffff;">鏈接顏色與背景色相同或相似,采用十六進(jìn)制表達(dá)色彩</a>
<!-- 鏈接顏色與背景色相同或相似,color采用顏色英文名稱表達(dá)色彩 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="color: white;">鏈接顏色與背景色相同或相似,采用顏色英文名稱表達(dá)色彩</a>
<!-- 鏈接顏色透明,color采用transparent值 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="color: transparent">鏈接顏色透明</a>
<!-- 鏈接文字設(shè)置為0,使得不可見 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="font-size: 0px;">鏈接文字字號(hào)為0像素</a>
<!-- marquee類暗鏈 -->
<!-- 將marquee的scrollamount屬性值調(diào)為較大值,使跑馬燈移動(dòng)速度超過人眼可見范圍,達(dá)到隱藏效果 -->
<marquee scrollamount="100000"><a href="https://www.h0ksd3.6dayxpj.com:8989">我的車速夠快,你也看不見我</a></marquee>
<!-- 將marquee的scrolldelay屬性值調(diào)為較大值,使跑馬燈移動(dòng)速度非常慢,很長(zhǎng)時(shí)間都不會(huì)在屏幕中出現(xiàn)該鏈接,達(dá)到隱藏效果 -->
<marquee scrolldelay="100000"><a href="https://www.h0ksd3.6dayxpj.com:8989">我發(fā)車夠慢,你也不容易發(fā)現(xiàn)我</a></marquee>
<!-- JS寫入CSS樣式類暗鏈 -->
<!-- 利用JavaScript的document.write方法寫入一個(gè)CSS樣式屬性display為none,或者visibility為hidden的層來包裹需要隱藏的鏈接,達(dá)到隱藏暗鏈的效果 -->
<script language="javascript" type="text/javascript">
? ? document.write("<div style=\'display:none;\'>");
</script>
<a href=https://www.h0ksd3.6dayxpj.com:8989>通過JavaScript寫入包裹該鏈接的隱藏層,使得鏈接不可見</a>
<script language="javascript" type="text/javascript">
? ? document.write("</div>");?
</script>
<!-- JS修改CSS樣式類暗鏈 -->
<!-- 利用JavaScript修改CSS樣式屬性display為none,或者visibility為hidden來達(dá)到隱藏的效果 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" id="link1">通過JavaScript修改了本鏈接可見屬性設(shè)置為隱藏,使得鏈接不可見</a>
<script language="javascript" type="text/javascript">
? ? document.getElementById("link1").style.display = "none";
</script>
<!-- z-index類暗鏈 -->
<!-- 用z-index屬性堆疊遮擋,z-index值越小堆疊越靠后 -->
<div id="container" style="position: relative;">
? ? <div id="box1"
? ? ? ? style="position: absolute; top: 0; left: 0; width: 90%; height: 100px; background-color: yellow; z-index: 999;">
? ? ? ? 我是一個(gè)div層,這一層下面隱藏著鏈接
? ? </div>
? ? <div id="box2">
? ? ? ? <a href="https://www.h0ksd3.6dayxpj.com:8989">被z-index較大的div層把我遮擋了,你也看不見我</a>
? ? </div>
</div>
<!-- iframe內(nèi)聯(lián)框架類暗鏈 -->
<!-- 利用 iframe 創(chuàng)建隱藏的內(nèi)聯(lián)框架,frameborder設(shè)置邊框?qū)挾葹?,width寬度或height高度設(shè)置為0時(shí),就不可見 -->
<iframe src="https://httpbin.org/get" frameborder="10px" width="0px"
? ? height="0px">我是一個(gè)iframe內(nèi)鏈框架,frameborder為0,寬度為0時(shí)或高度為0時(shí),你就看不見我了</iframe>
<!-- 重定向方式暗鏈 -->
<!-- 采用setTimeout,在跳轉(zhuǎn)到正常網(wǎng)站頁面前植入暗鏈,等待很短時(shí)間就跳轉(zhuǎn)到正常頁面,用戶不易察覺 -->
<script>setTimeout('window.location="index.html"', 0.1)</script>
<body leftmargin="0" topmargin="0" scroll="no">
? ? <a href="https://h0ksd3.6dayxpj.com:8989">新葡京娛樂城</a>
</body>
<!-- 采用meta標(biāo)簽,通過設(shè)置http-equiv為refresh,結(jié)合content中攜帶需跳轉(zhuǎn)的鏈接和較短等待時(shí)間,來實(shí)現(xiàn)重定向,不過該種方式很容易被用戶發(fā)現(xiàn)異常 -->
<head>
? ? <meta http-equiv="refresh" content="1;url=https://h0ksd3.6dayxpj.com:8989" />
</head>
<!-- meta標(biāo)簽類暗鏈 -->
<!-- 設(shè)置meta的name屬性值為keywords,content為包含暗鏈的文字,或通過十進(jìn)制或十六進(jìn)制的HTML編碼或HTML實(shí)體編碼方式逃避靜態(tài)爬蟲爬取后不做解碼處理的方式 -->
<head>
? ? <!-- 用于搜索引擎SEO -->
? ? <meta name="keywords" content="澳門新普京最新官方網(wǎng)站【abcd.com】" />
? ? <!-- 采用十進(jìn)制的HTML編碼 -->
? ? <meta name="keywords"
? ? ? ? content="澳门新普京最新官方网站【abcd.com】" />
? ? <!-- 采用十六進(jìn)制的HTML編碼 -->
? ? <meta name="keywords"
? ? ? ? content="澳门新普京最新官方网站【abcd.com】" />
? ? <!-- 采用HTML實(shí)體編碼 -->
? ? <meta name="keywords" content="澳門新普京最新官方網(wǎng)站【abcd.com】" />
</head>
```
我們可以根據(jù)此構(gòu)造出一個(gè)具有暗鏈的網(wǎng)站,然后利用代碼去檢測(cè)
# 什么是CSSOM
來看看chatgpt怎么說
>CSSOM(CSS Object Model)是指CSS對(duì)象模型,它是一種表示和操作CSS樣式信息的API(應(yīng)用程序接口)。類似于DOM(文檔對(duì)象模型)用于操作HTML文檔的結(jié)構(gòu)和內(nèi)容,CSSOM用于操作和控制CSS樣式的規(guī)則、屬性和值。
CSSOM提供了一組接口和方法,允許開發(fā)人員通過JavaScript訪問和修改CSS樣式信息。它可以用于動(dòng)態(tài)地創(chuàng)建、修改或刪除CSS規(guī)則,以及獲取和修改元素的CSS屬性和值。
通過CSSOM,開發(fā)人員可以實(shí)現(xiàn)一些常見的樣式操作,例如:
動(dòng)態(tài)地改變?cè)氐臉邮剑热缧薷谋尘邦伾?、字體大小等。
動(dòng)態(tài)地添加、刪除或修改CSS規(guī)則,從而改變整個(gè)文檔的樣式。
訪問和獲取元素的計(jì)算樣式(computed style),即應(yīng)用在元素上的最終樣式值。
操作CSS動(dòng)畫和過渡效果,包括啟動(dòng)、停止或修改動(dòng)畫。
CSSOM的主要優(yōu)勢(shì)之一是可以與DOM無縫集成,通過將CSS樣式與HTML文檔結(jié)構(gòu)和內(nèi)容分開,可以實(shí)現(xiàn)更好的可維護(hù)性和靈活性。它在前端開發(fā)中扮演著重要的角色,讓開發(fā)人員能夠以編程的方式操控和控制頁面的樣式外觀和交互效果。
我們通過playwright爬蟲,通過執(zhí)行js函數(shù),將所有暗鏈檢測(cè)中可能使用到的css屬性全部獲取到,具體的方法為:
```javascript
function traverseDOMTree(node) {
? ? ? ? ? ? ? ? ? // 檢查節(jié)點(diǎn)是否為元素節(jié)點(diǎn)
? ? ? ? ? ? ? ? ? cssom = []
? ? ? ? ? ? ? ? ? if (node.nodeType === Node.ELEMENT_NODE) {
? ? ? ? ? ? ? ? ? ? // 輸出節(jié)點(diǎn)的 class 屬性
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? const e = node;
? ? ? ? ? ? ? ? ? const styles = window.getComputedStyle(e);
? ? ? ? ? ? ? ? ? const ans = {
? ? ? ? ? ? ? ? ? ? ? ? 'tag_name':e.tagName,
? ? ? ? ? ? ? ? ? ? ? ? 'attribute_content':e.hasAttribute('content') ? e.attributes['content'].value : '',
? ? ? ? ? ? ? ? ? ? ? ? 'background_color':styles['background-color'],
? ? ? ? ? ? ? ? ? ? ? ? 'color':styles['color'],
? ? ? ? ? ? ? ? ? ? ? ? 'display':styles['display'],
? ? ? ? ? ? ? ? ? ? ? ? 'font_size':styles['font-size'],
? ? ? ? ? ? ? ? ? ? ? ? 'frameborder':e.hasAttribute('frameborder') ? e.attributes['frameborder'].value : '',
? ? ? ? ? ? ? ? ? ? ? ? 'height':styles['height'],
? ? ? ? ? ? ? ? ? ? ? ? 'href':e.href,
? ? ? ? ? ? ? ? ? ? ? ? 'http_equiv':e.hasAttribute('http-equiv') ? e.attributes['http-equiv'].value : '',
? ? ? ? ? ? ? ? ? ? ? ? 'language':e.hasAttribute('language') ? e.attributes['language'].value : '',
? ? ? ? ? ? ? ? ? ? ? ? 'left':styles['left'],
? ? ? ? ? ? ? ? ? ? ? ? 'position':styles['position'],
? ? ? ? ? ? ? ? ? ? ? ? 'scroll_delay':e.hasAttribute('scrolldelay') ? e.attributes['scrolldelay'].value : '',
? ? ? ? ? ? ? ? ? ? ? ? 'src':e.hasAttribute('src') ? e.attributes['src'].value : '',
? ? ? ? ? ? ? ? ? ? ? ? 'scroll_amount':e.hasAttribute('scrollamount') ? e.attributes['scrollamount'].value : '',
? ? ? ? ? ? ? ? ? ? ? ? 'top':styles['top'],
? ? ? ? ? ? ? ? ? ? ? ? 'width':styles['width'],
? ? ? ? ? ? ? ? ? ? ? ? 'visibility':styles['visibility'],
? ? ? ? ? ? ? ? ? ? ? ? 'z_index':styles['z-index'],
? ? ? ? ? ? ? ? ? ? ? ? 'children':[]
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? // 遍歷所有子節(jié)點(diǎn)
? ? ? ? ? ? ? ? ? for (let i = 0; i < node.childNodes.length; i++) {
? ? ? ? ? ? ? ? ? ? const childNode = node.childNodes[i];
? ? ? ? ? ? ? ? ? ? // 遞歸遍歷子節(jié)點(diǎn)
? ? ? ? ? ? ? ? ? ? if (childNode.nodeType === Node.ELEMENT_NODE) {
? ? ? ? ? ? ? ? ? ? ? const x = traverseDOMTree(childNode);
? ? ? ? ? ? ? ? ? ? ? ans['children'].push(x)
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? return ans;
}
```
然后我們利用playwright去執(zhí)行這一段js代碼即可
```python
cssom_json = await page.evaluate(js_init_script.TraverseDOMTree.eval_traver_se_dom_tree_script())
```
獲取到的結(jié)構(gòu)為:
```json
"cssom_view": {
"tag_name": "HTML",
"attribute_content": "",
"background_color": "rgba(0, 0, 0, 0)",
"color": "rgb(0, 0, 0)",
"display": "block",
"font_size": "16px",
"frameborder": "",
"height": "251.312px",
"href": null,
"http_equiv": "",
"language": "",
"left": "auto",
"position": "static",
"scroll_delay": "",
"src": "",
"scroll_amount": "",
"top": "auto",
"width": "1280px",
"visibility": "visible",
"z_index": "auto",
"children": []
```
children里面也是這樣的結(jié)構(gòu)。
# 檢測(cè)過程
## 編寫檢測(cè)配置文件
首先,由于暗鏈的放置方法是無窮的,上面的例子只是其中一小部分,所以考慮使用poc的方式來動(dòng)態(tài)配置檢測(cè)的規(guī)則
下面是根據(jù)上面的特征,編寫的一些poc文件
### z-index類堆疊暗鏈
```yml
nodes:
? - node_name: 'father-brother'
? ? css_rules:
? ? ? - css_name: 'z_index'
? ? ? ? value: '>100'
rule_name: 'z-index類暗鏈'
description: '用z-index屬性堆疊遮擋,z-index值越小堆疊越靠后'
```
### 顏色
```yml
nodes:
? - node_name: 'own'
? ? css_rules:
? ? ? - css_name: 'color'
? ? ? ? value: '=#ffffff'
rule_name: '鏈接顏色和文字類暗鏈'
description: '鏈接顏色與背景色相同或相似,color采用十六進(jìn)制表達(dá)色彩'
```
```yml
nodes:
? - node_name: 'own'
? ? css_rules:
? ? ? - css_name: 'color'
? ? ? ? value: '=transparent'
rule_name: '鏈接顏色和文字類暗鏈'
description: '鏈接顏色透明,color采用transparent值'
```
```yml
nodes:
? - node_name: 'own'
? ? css_rules:
? ? ? - css_name: 'color'
? ? ? ? value: '=white'
rule_name: '鏈接顏色和文字類暗鏈'
description: '鏈接顏色與背景色相同或相似,color采用顏色英文名稱表達(dá)色彩'
```
### 字體大小
```yml
nodes:
? - node_name: 'own'
? ? css_rules:
? ? ? - css_name: 'font_size'
? ? ? ? value: '=0'
rule_name: '鏈接顏色和文字類暗鏈'
description: '鏈接文字設(shè)置為0,使得不可見'
```
### 跑馬燈
```yml
nodes:
? - node_name: 'father'
? ? tag_rules:
? ? ? - tag_name: 'marquee'
? ? ? ? attribute_name: 'scrolldelay'
? ? ? ? attribute_value: '>100'
rule_name: 'marquee類暗鏈'
description: '將marquee的scrolldelay屬性值調(diào)為較大值,使跑馬燈移動(dòng)速度非常慢,很長(zhǎng)時(shí)間都不會(huì)在屏幕中出現(xiàn)該鏈接,達(dá)到隱藏效果'
```
```yml
nodes:
? - node_name: 'father'
? ? tag_rules:
? ? ? - tag_name: 'marquee'
? ? ? ? attribute_name: 'scrollamount'
? ? ? ? attribute_value: '>100'
rule_name: 'marquee類暗鏈'
description: '將marquee的scrollamount屬性值調(diào)為較大值,使跑馬燈移動(dòng)速度超過人眼可見范圍,達(dá)到隱藏效果'
```
### 可見性
```yml
nodes:
? - node_name: 'own'
? ? css_rules:
? ? ? - css_name: 'position'
? ? ? ? value: '=absolute'
? ? ? - css_name: 'top'
? ? ? ? value: '<0'
? ? ? - css_name: 'left'
? ? ? ? value: '<0'
rule_name: 'position位置類暗鏈'
description: 'position位置樣式,將元素的top、left位置設(shè)置成負(fù)數(shù),讓元素處于可視區(qū)外'
```
```yml
nodes:
? - node_name: 'own'
? ? css_rules:
? ? ? - css_name: 'visibility'
? ? ? ? value: '=hidden'
rule_name: 'visibility 隱藏類暗鏈'
description: ''
```
## 解析檢測(cè)配置文件,并進(jìn)行檢測(cè)
### 定義規(guī)則文件的結(jié)構(gòu)
```java
public class DarkCheckRule {
? ? private String ruleName;
? ? private String description;
? ? private List<DarkCheckRuleNode> nodes;
}
public class DarkCheckRuleNode {
? ? private String nodeName;
? ? private List<DarkCheckNodeCssRule> cssRules;
? ? private List<DarkCheckNodeTag> tagRules;
}
public class DarkCheckNodeCssRule {
? ? private String cssName;
? ? private String value;
}
public class DarkCheckNodeTag {
? ? private String tagName;
? ? private String attributeName;
? ? private String attributeValue;
}
```
規(guī)則分為兩種,第一是檢測(cè)最終css屬性,第二是檢測(cè)標(biāo)簽、屬性和值。
### 將yml內(nèi)容反序列化成規(guī)則對(duì)象
```java
// 讀取文件內(nèi)容
?public static String getFileContent(String fileName, Boolean absolutePath) {
? ? ? ? if (absolutePath) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? return getFileContent(new File(new File(".").getCanonicalPath() + "/" + fileName));
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? ? ? return "";
? ? ? ? } else {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? return getFileContent(new File(fileName));
? ? ? ? ? ? }catch (Exception e){
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? ? ? return "";
? ? ? ? }
? ? }
public static Map<String, Object> toMap(String yamlString) {
? ? ? ? Yaml yaml = new Yaml();
? ? ? ? return yaml.load(yamlString);
? ? }
public static Map<String, Object> loadFromFile2Map(String fileName) {
? ? ? ? return toMap(FileUtils.getFileContent(fileName, false));
? ? }
/**
? ? ?* 對(duì)象轉(zhuǎn)換成Json
? ? ?*
? ? ?* @param object Object
? ? ?* @return String
? ? ?*/
? ? public static String toJson(Object object) {
? ? ? ? StringWriter sw = new StringWriter();
? ? ? ? if (Objects.isNull(object)) {
? ? ? ? ? ? return EMPTY_JSON_OBJECT;
? ? ? ? }
? ? ? ? try {
? ? ? ? ? ? MAPPER.writeValue(MAPPER.getFactory().createGenerator(sw), object);
? ? ? ? } catch (Exception ex) {
? ? ? ? ? ? LOGGER.error("Object to json occur error, detail:", ex);
? ? ? ? }
? ? ? ? return sw.toString();
? ? }
public static <T> T toObject(String jsonString, Class<T> tClass) {
? ? ? ? if (Objects.isNull(jsonString) || jsonString.trim().isEmpty()) {
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? try {
? ? ? ? ? ? return MAPPER.readValue(jsonString, tClass);
? ? ? ? } catch (Exception ex) {
? ? ? ? ? ? ex.printStackTrace();
//? ? ? ? ? ? LOGGER.error("Json to object occur error, detail:", ex);
? ? ? ? }
? ? ? ? return null;
? ? }
```
然后調(diào)用上述工具類
```java
?DarkCheckRule darkCheckRule = Json.toObject(Json.toJson(YamlUtils.loadFromFile2Map(dir1.getAbsolutePath())), DarkCheckRule.class);
```
### 檢測(cè)過程
首先,暗鏈肯定是鏈接,所以首先應(yīng)該遍歷這個(gè)cssom的json,然后找到A標(biāo)簽等于目標(biāo)鏈接的,再對(duì)該標(biāo)簽進(jìn)行特征檢測(cè)
```java
if (cssomView.getTagName().equalsIgnoreCase("A")) {
? ? ? ? ? ? if (cssomView.getHref().equalsIgnoreCase(targetUrl)
? ? ? ? ? ? ? ? ? ? || cssomView.getSrc().equalsIgnoreCase(targetUrl)) {
? ? ? ? ? ? ? ? // TODO: 2023/5/10 開始檢測(cè)
? ? ? ? ? ? ? ? for (DarkCheckRule darkCheckRule : darkCheckRules) {
? ? ? ? ? ? ? ? ? ? if (Boolean.TRUE.equals(check(darkCheckRule, cssomView))) {
? ? ? ? ? ? ? ? ? ? ? ? // TODO: 2023/5/10 說明有匹配的
? ? ? ? ? ? ? ? ? ? ? ? checkAns.add(darkCheckRule.getRuleName() + "-" + darkCheckRule.getDescription());
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return;
? ? ? ? }
```
下面是檢測(cè)某一個(gè)規(guī)則的方法
```java
public Boolean check(DarkCheckRule darkCheckRule, NewCssomView cssomView) {
? ? ? ? // TODO: 2023/5/10
? ? ? ? List<DarkCheckRuleNode> darkCheckRuleNodes = darkCheckRule.getNodes();
? ? ? ? int flag = 0;
? ? ? ? for (DarkCheckRuleNode darkCheckRuleNode : darkCheckRuleNodes) {
? ? ? ? ? ? if (Boolean.FALSE.equals(checkOneNode(darkCheckRuleNode, cssomView))) {
? ? ? ? ? ? ? ? // TODO: 2023/5/10 需要都滿足才行
? ? ? ? ? ? ? ? flag = 1;
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (flag == 0) {
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? return false;
? ? }
/**
? ? ?* 檢測(cè)規(guī)則中的某一個(gè)規(guī)則節(jié)點(diǎn)
? ? ?*
? ? ?* @param darkCheckRuleNode
? ? ?* @param cssomView
? ? ?* @return
? ? ?*/
? ? public Boolean checkOneNode(DarkCheckRuleNode darkCheckRuleNode, NewCssomView cssomView) {
? ? ? ? List<DarkCheckNodeCssRule> darkCheckNodeCssRules = darkCheckRuleNode.getCssRules();
? ? ? ? if (darkCheckRuleNode.getNodeName().equalsIgnoreCase("own")) {
? ? ? ? ? ? // TODO: 2023/5/10 檢測(cè)自己
? ? ? ? ? ? return getOneNodeResult(darkCheckRuleNode, cssomView);
? ? ? ? } else if (darkCheckRuleNode.getNodeName().equalsIgnoreCase("children")) {
? ? ? ? ? ? // TODO: 2023/5/15 獲取所有本層子節(jié)點(diǎn),不考慮遞歸,只要有一個(gè)滿足即可
? ? ? ? ? ? for (NewCssomView newCssomView : cssomView.getChildren()) {
? ? ? ? ? ? ? ? if (Boolean.TRUE.equals(getOneNodeResult(darkCheckRuleNode, newCssomView))) {
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return false;
? ? ? ? } else if (darkCheckRuleNode.getNodeName().equalsIgnoreCase("father")) {
? ? ? ? ? ? // TODO: 2023/5/10 檢測(cè)父級(jí),只要有一個(gè)父級(jí)滿足即可
? ? ? ? ? ? while (true) {
? ? ? ? ? ? ? ? if (Objects.isNull(cssomView.getFather())) break;
? ? ? ? ? ? ? ? if (Boolean.TRUE.equals(getOneNodeResult(darkCheckRuleNode, cssomView.getFather()))) {
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
//? ? ? ? ? ? ? ? System.out.println("1");
? ? ? ? ? ? ? ? return checkOneNode(darkCheckRuleNode, cssomView.getFather());
? ? ? ? ? ? }
? ? ? ? ? ? return false;
? ? ? ? } else if (darkCheckRuleNode.getNodeName().equalsIgnoreCase("brother")) {
? ? ? ? ? ? // TODO: 2023/5/10 檢測(cè)同級(jí)節(jié)點(diǎn)
? ? ? ? ? ? // TODO: 2023/5/15 親兄弟
? ? ? ? ? ? for (NewCssomView newCssomView : cssomView.getFather().getChildren()) {
? ? ? ? ? ? ? ? if (Boolean.TRUE.equals(getOneNodeResult(darkCheckRuleNode,newCssomView))){
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return false;
? ? ? ? } else if (darkCheckRuleNode.getNodeName().equalsIgnoreCase("father-brother")) {
? ? ? ? ? ? // TODO: 2023/5/15 父級(jí)的親兄弟
? ? ? ? ? ? while (true){
? ? ? ? ? ? ? ? if (Objects.isNull(cssomView.getFather()))break;
? ? ? ? ? ? ? ? for (NewCssomView newCssomView : cssomView.getFather().getChildren()){
? ? ? ? ? ? ? ? ? ? if (Boolean.TRUE.equals(getOneNodeResult(darkCheckRuleNode,newCssomView))){
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return checkOneNode(darkCheckRuleNode,cssomView.getFather());
? ? ? ? ? ? }
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? return false;
? ? }
public Boolean getOneNodeResult(DarkCheckRuleNode darkCheckRuleNode, NewCssomView cssomView) {
? ? ? ? int flag = 0;
? ? ? ? // TODO: 2023/5/15檢測(cè)完所有的CCSRULE
? ? ? ? if (Objects.nonNull(darkCheckRuleNode.getCssRules())){
? ? ? ? ? ? for (DarkCheckNodeCssRule darkCheckNodeCssRule : darkCheckRuleNode.getCssRules()) {
? ? ? ? ? ? ? ? if (Boolean.FALSE.equals(checkOneCssRule(darkCheckNodeCssRule, cssomView))) {
? ? ? ? ? ? ? ? ? ? flag = 1;
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (Objects.nonNull(darkCheckRuleNode.getTagRules())){
? ? ? ? ? ? for (DarkCheckNodeTag darkCheckNodeTag : darkCheckRuleNode.getTagRules()) {
? ? ? ? ? ? ? ? if (Boolean.FALSE.equals(checkOneTagRule(darkCheckNodeTag, cssomView))) {
? ? ? ? ? ? ? ? ? ? flag = 1;
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (flag == 0) {
? ? ? ? ? ? // TODO: 2023/5/10 都成功
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? return false;
? ? }
/**
? ? ?* 檢測(cè)某一個(gè)css的結(jié)果
? ? ?*
? ? ?* @param darkCheckNodeCssRule
? ? ?* @param cssomView
? ? ?* @return
? ? ?*/
? ? public Boolean checkOneCssRule(DarkCheckNodeCssRule darkCheckNodeCssRule, NewCssomView cssomView) {
? ? ? ? NewCssomView father = cssomView.getFather();
? ? ? ? cssomView.setFather(null);
? ? ? ? Map<String, Object> x = Json.toMap(Json.toJson(cssomView));
? ? ? ? cssomView.setFather(father);
? ? ? ? try {
? ? ? ? ? ? if (Objects.nonNull(x.get(darkCheckNodeCssRule.getCssName()))) {
? ? ? ? ? ? ? ? String value = darkCheckNodeCssRule.getValue();
? ? ? ? ? ? ? ? String aaa = (String) x.getOrDefault(darkCheckNodeCssRule.getCssName(), "0");
? ? ? ? ? ? ? ? if (value.startsWith("<")) {
? ? ? ? ? ? ? ? ? ? Integer xxx = MathUtils.toInt(aaa);
? ? ? ? ? ? ? ? ? ? if (xxx < MathUtils.toInt(value)) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (value.startsWith(">")) {
? ? ? ? ? ? ? ? ? ? Integer xxx = MathUtils.toInt(aaa);
? ? ? ? ? ? ? ? ? ? if (xxx > MathUtils.toInt(value)) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (value.startsWith("=")) {
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? if (aaa.toLowerCase().contains(value.substring(1).toLowerCase())) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (value.equalsIgnoreCase("=")) {
? ? ? ? ? ? ? ? ? ? Integer xxx = MathUtils.toInt(aaa);
? ? ? ? ? ? ? ? ? ? if (xxx == MathUtils.toInt(value)) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? }
? ? ? ? return false;
? ? }
public Boolean checkOneTagRule(DarkCheckNodeTag darkCheckNodeTag, NewCssomView cssomView) {
? ? ? ? NewCssomView father = cssomView.getFather();
? ? ? ? cssomView.setFather(null);
? ? ? ? Map<String, Object> x = Json.toMap(Json.toJson(cssomView));
? ? ? ? cssomView.setFather(father);
? ? ? ? try {
? ? ? ? ? ? if (Objects.nonNull(x.get("tag_name"))) {
? ? ? ? ? ? ? ? String tagName = x.getOrDefault("tag_name", "").toString();
? ? ? ? ? ? ? ? Integer trueNumber = 0;
? ? ? ? ? ? ? ? String conditionValue = darkCheckNodeTag.getAttributeValue();
? ? ? ? ? ? ? ? if (tagName.equalsIgnoreCase(darkCheckNodeTag.getTagName())) {
? ? ? ? ? ? ? ? ? ? String conditionName = darkCheckNodeTag.getAttributeName();
? ? ? ? ? ? ? ? ? ? if (conditionName.equalsIgnoreCase("scrollamount")) {
? ? ? ? ? ? ? ? ? ? ? ? String trueValue = cssomView.getScrollAmount();
? ? ? ? ? ? ? ? ? ? ? ? trueNumber = MathUtils.toInt(trueValue);
? ? ? ? ? ? ? ? ? ? } else if (conditionName.equalsIgnoreCase("scrolldelay")) {
? ? ? ? ? ? ? ? ? ? ? ? trueNumber = MathUtils.toInt(cssomView.getScrollDelay());
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? Integer conditionNumber = MathUtils.toInt(conditionValue);
? ? ? ? ? ? ? ? if (conditionValue.startsWith(">")) {
? ? ? ? ? ? ? ? ? ? if (trueNumber > conditionNumber) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (conditionValue.startsWith("<")) {
? ? ? ? ? ? ? ? ? ? if (trueNumber < conditionNumber) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (conditionValue.startsWith("=")) {
? ? ? ? ? ? ? ? ? ? if (trueNumber == conditionNumber) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? }
? ? ? ? return false;
? ? }
```
接下來要做的就是進(jìn)一步完善檢測(cè)poc即可