diff --git a/.github/workflows/anti-spam.yml b/.github/workflows/anti-spam.yml new file mode 100644 index 0000000..5fdd21c --- /dev/null +++ b/.github/workflows/anti-spam.yml @@ -0,0 +1,134 @@ +name: Anti-Spam + +on: + issues: + types: [opened, edited] + +permissions: + issues: write + +jobs: + check-spam: + runs-on: ubuntu-latest + steps: + - name: Check for spam + uses: actions/github-script@v7 + with: + script: | + const issue = context.payload.issue; + const title = (issue.title || '').toLowerCase(); + const body = (issue.body || '').toLowerCase(); + const text = title + ' ' + body; + + // 博彩/赌球类 + const gamblingPatterns = [ + /世界杯.*买球/, /买球.*世界杯/, + /世界杯.*下注/, /世界杯.*竞猜/, + /世界杯.*投注/, /世界杯.*押注/, + /世界杯.*彩票/, /世界杯.*平台/, + /世界杯.*app/, /世界杯.*软件/, + /世界杯.*网站/, /世界杯.*网址/, + /足球.*买球/, /买球.*足球/, + /足球.*投注/, /足球.*押注/, + /足球.*竞猜/, /足球.*平台/, + /篮球.*买球/, /篮球.*投注/, + /体育.*投注/, /体育.*竞猜/, + /体育.*买球/, /体育.*押注/, + /赌球/, /赌博.*网站/, /赌博.*平台/, + /博彩/, /博彩.*网站/, /博彩.*平台/, + /正规.*买球/, /官方.*买球/, + /买球.*网站/, /买球.*app/, + /买球.*软件/, /买球.*网址/, + /买球.*平台/, /买球.*技巧/, + /投注.*网站/, /投注.*平台/, + /押注.*网站/, /押注.*平台/, + /竞猜.*网站/, /竞猜.*平台/, + /彩票.*网站/, /彩票.*平台/, + /欧洲杯.*买球/, /欧冠.*买球/, + /nba.*买球/, /nba.*投注/, + ]; + + // 色情/交友类 + const adultPatterns = [ + /约炮/, /一夜情/, /外围/, + /包养/, /援交/, /陪聊/, + /成人.*网站/, /成人.*视频/, + /av.*网站/, /黄色.*网站/, + ]; + + // 贷款/金融诈骗类 + const financePatterns = [ + /秒到账.*贷款/, /无抵押.*贷款/, + /征信.*贷款/, /黑户.*贷款/, + /快速.*放款/, /私人.*放贷/, + /刷单/, /兼职.*日入/, /兼职.*月入/, + /网赚/, /躺赚/, /被动收入.*平台/, + /虚拟货币.*投资/, /usdt.*投资/, + /炒币.*平台/, /数字货币.*平台/, + ]; + + // 垃圾推广类 + const spamPromoPatterns = [ + /代刷/, /粉丝.*购买/, /涨粉/, + /seo.*优化/, /快速排名/, + /微商/, /代理.*招募/, + ]; + + // 账号特征检测(新账号 + 无 contribution) + const allPatterns = [ + ...gamblingPatterns, + ...adultPatterns, + ...financePatterns, + ...spamPromoPatterns, + ]; + + const isSpam = allPatterns.some(pattern => pattern.test(text)); + + // 额外检测:标题超短且含可疑关键词(常见于批量刷单) + const suspiciousShort = title.length < 10 && /(买球|投注|博彩|赌博|下注|押注)/.test(title); + + if (isSpam || suspiciousShort) { + // 确保 spam label 存在 + try { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'spam', + color: 'e4e669', + description: 'Spam issue' + }); + } catch (e) { + // label 已存在,忽略 + } + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: '此 issue 已被自动识别为垃圾内容并关闭。\n\nThis issue has been automatically identified as spam and closed.' + }); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['spam'] + }); + + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed', + state_reason: 'not_planned' + }); + + await github.rest.issues.lock({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + lock_reason: 'spam' + }); + + console.log(`Closed spam issue #${issue.number}: ${issue.title}`); + } diff --git a/package.json b/package.json index 2ed4b45..cd81f75 100644 --- a/package.json +++ b/package.json @@ -194,6 +194,6 @@ "picomatch": "^4.0.4", "tar": "^7.5.13", "immutable": "^5.1.5", - "ajv": ">=6.14.0" + "ajv": "^6.14.0" } } diff --git a/resources/libwcdb_api.dylib b/resources/libwcdb_api.dylib index 208a952..a9a6ccd 100755 Binary files a/resources/libwcdb_api.dylib and b/resources/libwcdb_api.dylib differ diff --git a/resources/libwcdb_api.so b/resources/libwcdb_api.so index 7dc674d..7aa52f4 100755 Binary files a/resources/libwcdb_api.so and b/resources/libwcdb_api.so differ diff --git a/resources/linux/libwcdb_api.so b/resources/linux/libwcdb_api.so index 3505134..7aa52f4 100755 Binary files a/resources/linux/libwcdb_api.so and b/resources/linux/libwcdb_api.so differ diff --git a/resources/macos/libwcdb_api.dylib b/resources/macos/libwcdb_api.dylib index 208a952..a9a6ccd 100755 Binary files a/resources/macos/libwcdb_api.dylib and b/resources/macos/libwcdb_api.dylib differ diff --git a/resources/wcdb_api.dll b/resources/wcdb_api.dll index efc2929..0c98883 100644 Binary files a/resources/wcdb_api.dll and b/resources/wcdb_api.dll differ diff --git a/src/App.tsx b/src/App.tsx index ed66bab..4ad162e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -104,6 +104,7 @@ function App() { // 数据收集同意状态 const [showAnalyticsConsent, setShowAnalyticsConsent] = useState(false) + const [analyticsConsent, setAnalyticsConsent] = useState(null) const [showWaylandWarning, setShowWaylandWarning] = useState(false) @@ -253,6 +254,7 @@ function App() { // 协议已同意,检查数据收集同意状态 const consent = await configService.getAnalyticsConsent() const denyCount = await configService.getAnalyticsDenyCount() + setAnalyticsConsent(consent) // 如果未设置同意状态且拒绝次数小于2次,显示弹窗 if (consent === null && denyCount < 2) { setShowAnalyticsConsent(true) @@ -267,18 +269,21 @@ function App() { checkAgreement() }, []) - // 初始化数据收集 + // 初始化数据收集(仅在用户同意后) useEffect(() => { - cloudControl.initCloudControl() - }, []) + if (analyticsConsent === true) { + cloudControl.initCloudControl() + } + }, [analyticsConsent]) - // 记录页面访问 + // 记录页面访问(仅在用户同意后) useEffect(() => { + if (analyticsConsent !== true) return const path = location.pathname if (path && path !== '/') { cloudControl.recordPage(path) } - }, [location.pathname]) + }, [location.pathname, analyticsConsent]) const handleAgree = async () => { if (!agreementChecked) return @@ -297,6 +302,7 @@ function App() { const handleAnalyticsAllow = async () => { await configService.setAnalyticsConsent(true) + setAnalyticsConsent(true) setShowAnalyticsConsent(false) }