feat: add captcha-backed forum security hardening
This commit is contained in:
95
tests/Unit/AccountFarmDetectorTest.php
Normal file
95
tests/Unit/AccountFarmDetectorTest.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
use cPad\Plugins\Forum\Services\Security\AccountFarmDetector;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
uses(Tests\TestCase::class);
|
||||
|
||||
it('flags repeated posting patterns across multiple accounts', function () {
|
||||
config()->set('forum_bot_protection.account_farm', [
|
||||
'window_minutes' => 10,
|
||||
'register_attempt_threshold' => 10,
|
||||
'same_ip_users_threshold' => 5,
|
||||
'same_fingerprint_users_threshold' => 3,
|
||||
'same_pattern_users_threshold' => 2,
|
||||
'register_attempt_penalty' => 50,
|
||||
'same_ip_penalty' => 35,
|
||||
'same_fingerprint_penalty' => 40,
|
||||
'same_pattern_penalty' => 45,
|
||||
]);
|
||||
|
||||
Schema::dropIfExists('forum_posts');
|
||||
Schema::dropIfExists('forum_bot_device_fingerprints');
|
||||
Schema::dropIfExists('forum_bot_logs');
|
||||
|
||||
Schema::create('forum_bot_logs', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->string('action', 80);
|
||||
$table->unsignedTinyInteger('risk_score')->default(0);
|
||||
$table->string('decision', 20)->default('allow');
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('forum_bot_device_fingerprints', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
$table->string('fingerprint', 128)->nullable();
|
||||
$table->timestamp('first_seen')->nullable();
|
||||
$table->timestamp('last_seen')->nullable();
|
||||
$table->unsignedTinyInteger('risk_score')->default(0);
|
||||
$table->string('user_agent_hash', 64)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('forum_posts', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('thread_id')->nullable();
|
||||
$table->unsignedBigInteger('topic_id')->nullable();
|
||||
$table->string('source_ip_hash', 64)->nullable();
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
$table->longText('content')->nullable();
|
||||
$table->string('content_hash', 64)->nullable();
|
||||
$table->boolean('is_edited')->default(false);
|
||||
$table->timestamp('edited_at')->nullable();
|
||||
$table->unsignedInteger('spam_score')->default(0);
|
||||
$table->unsignedInteger('quality_score')->default(0);
|
||||
$table->unsignedInteger('ai_spam_score')->default(0);
|
||||
$table->unsignedInteger('ai_toxicity_score')->default(0);
|
||||
$table->unsignedInteger('behavior_score')->default(0);
|
||||
$table->unsignedInteger('link_score')->default(0);
|
||||
$table->integer('learning_score')->default(0);
|
||||
$table->unsignedInteger('risk_score')->default(0);
|
||||
$table->integer('trust_modifier')->default(0);
|
||||
$table->boolean('flagged')->default(false);
|
||||
$table->string('flagged_reason')->nullable();
|
||||
$table->boolean('moderation_checked')->default(false);
|
||||
$table->string('moderation_status')->nullable();
|
||||
$table->json('moderation_labels')->nullable();
|
||||
$table->json('moderation_meta')->nullable();
|
||||
$table->timestamp('last_ai_scan_at')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
|
||||
$hash = hash('sha256', 'buy cheap backlinks now');
|
||||
|
||||
foreach ([1, 2, 3] as $userId) {
|
||||
DB::table('forum_posts')->insert([
|
||||
'user_id' => $userId,
|
||||
'content' => 'buy cheap backlinks now',
|
||||
'content_hash' => $hash,
|
||||
'created_at' => now()->subMinutes(2),
|
||||
'updated_at' => now()->subMinutes(2),
|
||||
]);
|
||||
}
|
||||
|
||||
$result = app(AccountFarmDetector::class)->analyze(1, '203.0.113.10', null, 'forum_reply_create');
|
||||
|
||||
expect($result['score'])->toBe(45)
|
||||
->and($result['reasons'])->toContain('Posting patterns or repeated content overlap across multiple accounts.');
|
||||
});
|
||||
Reference in New Issue
Block a user