基于Cssom的暗鏈檢測技術(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)
# 什么是暗鏈
大部分的開源代碼在實現(xiàn)暗鏈檢測的時候都是直接判斷頁面里面有沒有敏感詞,如果有,就認為該鏈接為暗鏈。這種做法其實是有誤的。
違規(guī)鏈接應該分為:外鏈、內(nèi)鏈、死鏈和暗鏈。而暗鏈除了違規(guī),還應該具備“暗”這個看不見的特征。
## 暗鏈的特征
其實“暗鏈”就是看不見的網(wǎng)站鏈接,“暗鏈”在網(wǎng)站中的鏈接做得非常隱蔽,短時間內(nèi)不易被搜索引擎察覺。是做非法SEO的常用手段。
下面是一些特征
```html
<!-- 正常連接 -->
<a href="https://www.baidu.com">正常外鏈</a>
<!-- position位置類暗鏈 -->
<!-- position位置樣式,將元素的top、left位置設(shè)置成負數(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采用十六進制表達色彩 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="color: #ffffff;">鏈接顏色與背景色相同或相似,采用十六進制表達色彩</a>
<!-- 鏈接顏色與背景色相同或相似,color采用顏色英文名稱表達色彩 -->
<a href="https://www.h0ksd3.6dayxpj.com:8989" style="color: white;">鏈接顏色與背景色相同或相似,采用顏色英文名稱表達色彩</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;">鏈接文字字號為0像素</a>
<!-- marquee類暗鏈 -->
<!-- 將marquee的scrollamount屬性值調(diào)為較大值,使跑馬燈移動速度超過人眼可見范圍,達到隱藏效果 -->
<marquee scrollamount="100000"><a href="https://www.h0ksd3.6dayxpj.com:8989">我的車速夠快,你也看不見我</a></marquee>
<!-- 將marquee的scrolldelay屬性值調(diào)為較大值,使跑馬燈移動速度非常慢,很長時間都不會在屏幕中出現(xiàn)該鏈接,達到隱藏效果 -->
<marquee scrolldelay="100000"><a href="https://www.h0ksd3.6dayxpj.com:8989">我發(fā)車夠慢,你也不容易發(fā)現(xiàn)我</a></marquee>
<!-- JS寫入CSS樣式類暗鏈 -->
<!-- 利用JavaScript的document.write方法寫入一個CSS樣式屬性display為none,或者visibility為hidden的層來包裹需要隱藏的鏈接,達到隱藏暗鏈的效果 -->
<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來達到隱藏的效果 -->
<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;">
? ? ? ? 我是一個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時,就不可見 -->
<iframe src="https://httpbin.org/get" frameborder="10px" width="0px"
? ? height="0px">我是一個iframe內(nèi)鏈框架,frameborder為0,寬度為0時或高度為0時,你就看不見我了</iframe>
<!-- 重定向方式暗鏈 -->
<!-- 采用setTimeout,在跳轉(zhuǎn)到正常網(wǎng)站頁面前植入暗鏈,等待很短時間就跳轉(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標簽,通過設(shè)置http-equiv為refresh,結(jié)合content中攜帶需跳轉(zhuǎn)的鏈接和較短等待時間,來實現(xiàn)重定向,不過該種方式很容易被用戶發(fā)現(xiàn)異常 -->
<head>
? ? <meta http-equiv="refresh" content="1;url=https://h0ksd3.6dayxpj.com:8989" />
</head>
<!-- meta標簽類暗鏈 -->
<!-- 設(shè)置meta的name屬性值為keywords,content為包含暗鏈的文字,或通過十進制或十六進制的HTML編碼或HTML實體編碼方式逃避靜態(tài)爬蟲爬取后不做解碼處理的方式 -->
<head>
? ? <!-- 用于搜索引擎SEO -->
? ? <meta name="keywords" content="澳門新普京最新官方網(wǎng)站【abcd.com】" />
? ? <!-- 采用十進制的HTML編碼 -->
? ? <meta name="keywords"
? ? ? ? content="澳门新普京最新官方网站【abcd.com】" />
? ? <!-- 采用十六進制的HTML編碼 -->
? ? <meta name="keywords"
? ? ? ? content="澳门新普京最新官方网站【abcd.com】" />
? ? <!-- 采用HTML實體編碼 -->
? ? <meta name="keywords" content="澳門新普京最新官方網(wǎng)站【abcd.com】" />
</head>
```
我們可以根據(jù)此構(gòu)造出一個具有暗鏈的網(wǎng)站,然后利用代碼去檢測
# 什么是CSSOM
來看看chatgpt怎么說
>CSSOM(CSS Object Model)是指CSS對象模型,它是一種表示和操作CSS樣式信息的API(應用程序接口)。類似于DOM(文檔對象模型)用于操作HTML文檔的結(jié)構(gòu)和內(nèi)容,CSSOM用于操作和控制CSS樣式的規(guī)則、屬性和值。
CSSOM提供了一組接口和方法,允許開發(fā)人員通過JavaScript訪問和修改CSS樣式信息。它可以用于動態(tài)地創(chuàng)建、修改或刪除CSS規(guī)則,以及獲取和修改元素的CSS屬性和值。
通過CSSOM,開發(fā)人員可以實現(xiàn)一些常見的樣式操作,例如:
動態(tài)地改變元素的樣式,比如修改背景顏色、字體大小等。
動態(tài)地添加、刪除或修改CSS規(guī)則,從而改變整個文檔的樣式。
訪問和獲取元素的計算樣式(computed style),即應用在元素上的最終樣式值。
操作CSS動畫和過渡效果,包括啟動、停止或修改動畫。
CSSOM的主要優(yōu)勢之一是可以與DOM無縫集成,通過將CSS樣式與HTML文檔結(jié)構(gòu)和內(nèi)容分開,可以實現(xiàn)更好的可維護性和靈活性。它在前端開發(fā)中扮演著重要的角色,讓開發(fā)人員能夠以編程的方式操控和控制頁面的樣式外觀和交互效果。
我們通過playwright爬蟲,通過執(zhí)行js函數(shù),將所有暗鏈檢測中可能使用到的css屬性全部獲取到,具體的方法為:
```javascript
function traverseDOMTree(node) {
? ? ? ? ? ? ? ? ? // 檢查節(jié)點是否為元素節(jié)點
? ? ? ? ? ? ? ? ? cssom = []
? ? ? ? ? ? ? ? ? if (node.nodeType === Node.ELEMENT_NODE) {
? ? ? ? ? ? ? ? ? ? // 輸出節(jié)點的 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é)點
? ? ? ? ? ? ? ? ? for (let i = 0; i < node.childNodes.length; i++) {
? ? ? ? ? ? ? ? ? ? const childNode = node.childNodes[i];
? ? ? ? ? ? ? ? ? ? // 遞歸遍歷子節(jié)點
? ? ? ? ? ? ? ? ? ? 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)。
# 檢測過程
## 編寫檢測配置文件
首先,由于暗鏈的放置方法是無窮的,上面的例子只是其中一小部分,所以考慮使用poc的方式來動態(tài)配置檢測的規(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采用十六進制表達色彩'
```
```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采用顏色英文名稱表達色彩'
```
### 字體大小
```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)為較大值,使跑馬燈移動速度非常慢,很長時間都不會在屏幕中出現(xiàn)該鏈接,達到隱藏效果'
```
```yml
nodes:
? - node_name: 'father'
? ? tag_rules:
? ? ? - tag_name: 'marquee'
? ? ? ? attribute_name: 'scrollamount'
? ? ? ? attribute_value: '>100'
rule_name: 'marquee類暗鏈'
description: '將marquee的scrollamount屬性值調(diào)為較大值,使跑馬燈移動速度超過人眼可見范圍,達到隱藏效果'
```
### 可見性
```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è)置成負數(shù),讓元素處于可視區(qū)外'
```
```yml
nodes:
? - node_name: 'own'
? ? css_rules:
? ? ? - css_name: 'visibility'
? ? ? ? value: '=hidden'
rule_name: 'visibility 隱藏類暗鏈'
description: ''
```
## 解析檢測配置文件,并進行檢測
### 定義規(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ī)則分為兩種,第一是檢測最終css屬性,第二是檢測標簽、屬性和值。
### 將yml內(nèi)容反序列化成規(guī)則對象
```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));
? ? }
/**
? ? ?* 對象轉(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);
```
### 檢測過程
首先,暗鏈肯定是鏈接,所以首先應該遍歷這個cssom的json,然后找到A標簽等于目標鏈接的,再對該標簽進行特征檢測
```java
if (cssomView.getTagName().equalsIgnoreCase("A")) {
? ? ? ? ? ? if (cssomView.getHref().equalsIgnoreCase(targetUrl)
? ? ? ? ? ? ? ? ? ? || cssomView.getSrc().equalsIgnoreCase(targetUrl)) {
? ? ? ? ? ? ? ? // TODO: 2023/5/10 開始檢測
? ? ? ? ? ? ? ? for (DarkCheckRule darkCheckRule : darkCheckRules) {
? ? ? ? ? ? ? ? ? ? if (Boolean.TRUE.equals(check(darkCheckRule, cssomView))) {
? ? ? ? ? ? ? ? ? ? ? ? // TODO: 2023/5/10 說明有匹配的
? ? ? ? ? ? ? ? ? ? ? ? checkAns.add(darkCheckRule.getRuleName() + "-" + darkCheckRule.getDescription());
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return;
? ? ? ? }
```
下面是檢測某一個規(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;
? ? }
/**
? ? ?* 檢測規(guī)則中的某一個規(guī)則節(jié)點
? ? ?*
? ? ?* @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 檢測自己
? ? ? ? ? ? return getOneNodeResult(darkCheckRuleNode, cssomView);
? ? ? ? } else if (darkCheckRuleNode.getNodeName().equalsIgnoreCase("children")) {
? ? ? ? ? ? // TODO: 2023/5/15 獲取所有本層子節(jié)點,不考慮遞歸,只要有一個滿足即可
? ? ? ? ? ? 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 檢測父級,只要有一個父級滿足即可
? ? ? ? ? ? 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 檢測同級節(jié)點
? ? ? ? ? ? // 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 父級的親兄弟
? ? ? ? ? ? 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檢測完所有的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;
? ? }
/**
? ? ?* 檢測某一個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;
? ? }
```
接下來要做的就是進一步完善檢測poc即可