Skip to content

Commit

Permalink
WiP BanWarden
Browse files Browse the repository at this point in the history
  • Loading branch information
Xinecraft committed Oct 19, 2024
1 parent 8ddf507 commit 8968821
Show file tree
Hide file tree
Showing 239 changed files with 4,984 additions and 2,148 deletions.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,10 @@ MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=no-reply@minetrax.github.io
MAIL_FROM_NAME="${APP_NAME}"

# BanWarden
BANWARDEN_ENABLED=true
BANWARDEN_AI_INSIGHTS_ENABLED=true
BANWARDEN_SHOW_PUBLIC=true
BANWARDEN_DISCORD_WEBHHOOK_URL=
BANWARDEN_ALLOW_CONTROL_FROM_WEB=true
14 changes: 4 additions & 10 deletions app/Enums/PlayerPunishmentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,10 @@

final class PlayerPunishmentType extends Enum
{
const PLAYER_BAN = 'PLAYER_BAN';
const IP_BAN = 'IP_BAN';
const COMPOSITE_BAN = 'COMPOSITE_BAN';
const PLAYER_MUTE = 'PLAYER_MUTE';
const IP_MUTE = 'IP_MUTE';
const COMPOSITE_MUTE = 'COMPOSITE_MUTE';
const PLAYER_WARN = 'PLAYER_WARN';
const IP_WARN = 'IP_WARN';
const COMPOSITE_WARN = 'COMPOSITE_WARN';
const PLAYER_KICK = 'PLAYER_KICK';
const BAN = 'ban';
const MUTE = 'mute';
const WARN = 'warn';
const KICK = 'kick';

public function toArray(): mixed
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function indexOpen(Request $request)
'user.name',
'lastActor.name',
'lastCommentor.name',
AllowedFilter::custom('q', new FilterMultipleFields(['data', 'status'])),
AllowedFilter::custom('q', new FilterMultipleFields(['id', 'data', 'status'])),
])
->allowedSorts($fields)
->defaultSort('-updated_at')
Expand Down Expand Up @@ -142,7 +142,7 @@ public function indexClosed(Request $request)
'user.name',
'lastActor.name',
'lastCommentor.name',
AllowedFilter::custom('q', new FilterMultipleFields(['data', 'status'])),
AllowedFilter::custom('q', new FilterMultipleFields(['id', 'data', 'status'])),
])
->allowedSorts($fields)
->defaultSort('-updated_at')
Expand Down
14 changes: 12 additions & 2 deletions app/Http/Controllers/Admin/ServerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,12 @@ public function storeBungee(Request $request, GeolocationService $geolocationSer
'webquery_port' => 'nullable|numeric|min:0|max:65535|required_if_accepted:is_server_intel_enabled|different:join_port',
'name' => 'required',
'minecraft_version' => ['required', new EnumValue(ServerVersion::class)],
'settings' => 'sometimes',
'is_server_intel_enabled' => 'required|boolean',
'settings' => 'sometimes',
'settings.server_identifier' => 'nullable|alpha_dash',
'settings.is_skin_change_via_web_allowed' => 'required|boolean',
'settings.is_banwarden_enabled' => 'required|boolean',
'order' => 'nullable|numeric',
]);

$countryId = $geolocationService->getCountryIdFromIP($request->ip_address);
Expand All @@ -170,6 +174,7 @@ public function storeBungee(Request $request, GeolocationService $geolocationSer
'is_server_intel_enabled' => $request->is_server_intel_enabled,
'settings' => $request->settings,
'created_by' => $request->user()->id,
'order' => $request->order,
]);

if (! $request->webquery_port) {
Expand Down Expand Up @@ -276,8 +281,12 @@ public function updateBungee(Request $request, Server $server, GeolocationServic
'webquery_port' => 'nullable|numeric|min:0|max:65535|required_if_accepted:is_server_intel_enabled|different:join_port',
'name' => 'required',
'minecraft_version' => ['required', new EnumValue(ServerVersion::class)],
'settings' => 'sometimes',
'is_server_intel_enabled' => 'required|boolean',
'settings' => 'sometimes',
'settings.server_identifier' => 'nullable|alpha_dash',
'settings.is_skin_change_via_web_allowed' => 'required|boolean',
'settings.is_banwarden_enabled' => 'required|boolean',
'order' => 'nullable|numeric',
]);

$countryId = $geolocationService->getCountryIdFromIP($request->ip_address);
Expand All @@ -292,6 +301,7 @@ public function updateBungee(Request $request, Server $server, GeolocationServic
$server->settings = $request->settings;
$server->is_server_intel_enabled = $request->is_server_intel_enabled;
$server->country_id = $countryId;
$server->order = $request->order;
$server->updated_by = $request->user()->id;
$server->save();

Expand Down
3 changes: 2 additions & 1 deletion app/Http/Controllers/Admin/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public function index()
'last_login_at',
'roles.display_name',
'country.name',
AllowedFilter::custom('q', new FilterMultipleFields(['name', 'email', 'username'])),
'discord_user_id',
AllowedFilter::custom('q', new FilterMultipleFields(['name', 'email', 'username', 'discord_user_id'])),
])
->allowedSorts(['id', 'name', 'email', 'username', 'created_at', 'updated_at', 'country_id', 'last_login_at'])
->defaultSort('id')
Expand Down
238 changes: 238 additions & 0 deletions app/Http/Controllers/Api/ApiBanWardenController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
<?php

namespace App\Http\Controllers\Api;

use App\Models\Player;
use App\Models\PlayerPunishment;
use App\Models\Server;
use App\Services\GeolocationService;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Cache;

class ApiBanWardenController extends ApiController
{
public function postSyncPunishments(Request $request, GeolocationService $geolocationService)
{
$request->validate([
'data' => 'required|array',
'data.server_id' => 'required|numeric|exists:servers,id',
'data.punishments' => 'required|array',
'data.punishments.*.plugin_name' => 'required|in:litebans,libertybans',
'data.punishments.*.plugin_punishment_id' => 'required|string',
'data.punishments.*.type' => 'required|in:ban,kick,mute,warn',
'data.punishments.*.uuid' => 'nullable|string',
'data.punishments.*.ip_address' => 'nullable|ip',
'data.punishments.*.is_ipban' => 'required|boolean',
'data.punishments.*.start_at' => 'required|numeric',
'data.punishments.*.end_at' => 'nullable|numeric',
'data.punishments.*.reason' => 'nullable|string',
'data.punishments.*.server_scope' => 'nullable|string',
'data.punishments.*.origin_server_name' => 'nullable|string',
'data.punishments.*.creator_uuid' => 'nullable|string',
'data.punishments.*.creator_username' => 'nullable|string',
'data.punishments.*.remover_uuid' => 'nullable|string',
'data.punishments.*.remover_username' => 'nullable|string',
'data.punishments.*.removed_reason' => 'nullable|string',
'data.punishments.*.removed_at' => 'nullable|numeric',
'data.punishments.*.from_event' => 'required|in:punish,pardon,sync',
]);

$server = Server::where('id', $request->input('data.server_id'))->firstOrFail();
if (!$server->settings['is_banwarden_enabled']) {
return $this->error(__('BanWarden is disabled on this server. Please enable it from web.'), 'banwarden_disabled', 403);
}

DB::beginTransaction();
try {
$punishments = $request->input('data.punishments');
foreach ($punishments as $punishment) {
$playerUuid = Str::isUuid($punishment['uuid']) ? $punishment['uuid'] : null;
$creatorUuid = Str::isUuid($punishment['creator_uuid']) ? $punishment['creator_uuid'] : null;
$removerUuid = Str::isUuid($punishment['remover_uuid']) ? $punishment['remover_uuid'] : null;
// Find player id
$player = $playerUuid ? Player::where('uuid', $punishment['uuid'])->first() : null;

$startAtDate = Carbon::createFromTimestampMs($punishment['start_at']);
$endAtDate = $punishment['end_at'] ? Carbon::createFromTimestampMs($punishment['end_at']) : null;
$removedAtDate = $punishment['removed_at'] ? Carbon::createFromTimestampMs($punishment['removed_at']) : null;

// Server ID for scope and origin
$serverScope = $punishment['server_scope'];
$scopeServer = null;
if ($serverScope != "*" && $serverScope != null) {
$scopeServer = Server::where('settings->server_identifier', $serverScope)
->orWhere('name', $serverScope)
->first();
}
$originServerName = $punishment['origin_server_name'];
$originServer = null;
if ($originServerName != null) {
$originServer = Server::where('settings->server_identifier', $originServerName)
->orWhere('name', $originServerName)
->first();
}
if (!$originServer) {
$originServer = $server;
}

// Get country id from IP
$forGeoIp = str_replace(['%', '*'], '0', $punishment['ip_address']);
$countryId = $geolocationService->getCountryIdFromIP($forGeoIp);

PlayerPunishment::updateOrCreate([
'type' => $punishment['type'],
'plugin_punishment_id' => $punishment['plugin_punishment_id'],
'plugin_name' => $punishment['plugin_name'],
], [
'type' => $punishment['type'],
'uuid' => $playerUuid,
'ip_address' => $punishment['ip_address'],
'player_id' => $player?->id,
'is_ipban' => $punishment['is_ipban'],
'country_id' => $countryId,
'start_at' => $startAtDate,
'end_at' => $endAtDate,
'reason' => $punishment['reason'],
'server_scope' => $punishment['server_scope'],
'scope_server_id' => $scopeServer?->id,
'origin_server_name' => $punishment['origin_server_name'],
'origin_server_id' => $originServer?->id,
'creator_uuid' => $creatorUuid,
'creator_username' => $punishment['creator_username'],
'remover_uuid' => $removerUuid,
'remover_username' => $punishment['remover_username'],
'removed_reason' => $punishment['removed_reason'],
'removed_at' => $removedAtDate,
]);
}

DB::commit();

// Forget Metrics Cache
Cache::forget('banwarden.public.metrics');

return $this->success(null, __('Punishments synced successfully.'));
} catch (\Exception $e) {
DB::rollBack();
\Log::error($e);

return $this->error(__('Failed to sync punishments: :message', [
'message' => $e->getMessage(),
]), 'failed_to_sync_punishments', 500);
}
}

public function postReportPunishment(Request $request, GeolocationService $geolocationService)
{
$request->validate([
'data' => 'required|array',
'data.server_id' => 'required|numeric|exists:servers,id',
'data.plugin_name' => 'required|in:litebans,libertybans',
'data.plugin_punishment_id' => 'required|string',
'data.type' => 'required|in:ban,kick,mute,warn',
'data.uuid' => 'nullable|string',
'data.ip_address' => 'nullable|ip',
'data.is_ipban' => 'required|boolean',
'data.start_at' => 'required|numeric',
'data.end_at' => 'nullable|numeric',
'data.reason' => 'nullable|string',
'data.server_scope' => 'nullable|string',
'data.origin_server_name' => 'nullable|string',
'data.creator_uuid' => 'nullable|string',
'data.creator_username' => 'nullable|string',
'data.remover_uuid' => 'nullable|string',
'data.remover_username' => 'nullable|string',
'data.removed_reason' => 'nullable|string',
'data.removed_at' => 'nullable|numeric',
'data.from_event' => 'required|in:punish,pardon,sync',
]);

$server = Server::where('id', $request->input('data.server_id'))->firstOrFail();
if (!$server->settings['is_banwarden_enabled']) {
return $this->error(__('BanWarden is disabled on this server. Please enable it from web.'), 'banwarden_disabled', 403);
}

DB::beginTransaction();
try {
$punishment = $request->input('data');
$playerUuid = Str::isUuid($punishment['uuid']) ? $punishment['uuid'] : null;
$creatorUuid = Str::isUuid($punishment['creator_uuid']) ? $punishment['creator_uuid'] : null;
$removerUuid = Str::isUuid($punishment['remover_uuid']) ? $punishment['remover_uuid'] : null;

// Find player id
$player = $playerUuid ? Player::where('uuid', $playerUuid)->first() : null;

$startAtDate = Carbon::createFromTimestampMs($punishment['start_at']);
$endAtDate = $punishment['end_at'] ? Carbon::createFromTimestampMs($punishment['end_at']) : null;
$removedAtDate = $punishment['removed_at'] ? Carbon::createFromTimestampMs($punishment['removed_at']) : null;

// Server ID for scope and origin
$serverScope = $punishment['server_scope'];
$scopeServer = null;
if ($serverScope != "*" && $serverScope != null) {
$scopeServer = Server::where('settings->server_identifier', $serverScope)
->orWhere('name', $serverScope)
->first();
}
$originServerName = $punishment['origin_server_name'];
$originServer = null;
if ($originServerName != null) {
$originServer = Server::where('settings->server_identifier', $originServerName)
->orWhere('name', $originServerName)
->first();
}
if (!$originServer) {
$originServer = $server;
}

// Get country id from IP
$forGeoIp = str_replace(['%', '*'], '0', $punishment['ip_address']);
$countryId = $geolocationService->getCountryIdFromIP($forGeoIp);

PlayerPunishment::updateOrCreate([
'type' => $punishment['type'],
'plugin_punishment_id' => $punishment['plugin_punishment_id'],
'plugin_name' => $punishment['plugin_name'],
], [
'type' => $punishment['type'],
'uuid' => $playerUuid,
'ip_address' => $punishment['ip_address'],
'player_id' => $player?->id,
'is_ipban' => $punishment['is_ipban'],
'country_id' => $countryId,
'start_at' => $startAtDate,
'end_at' => $endAtDate,
'reason' => $punishment['reason'],
'server_scope' => $punishment['server_scope'],
'scope_server_id' => $scopeServer?->id,
'origin_server_name' => $punishment['origin_server_name'],
'origin_server_id' => $originServer?->id,
'creator_uuid' => $creatorUuid,
'creator_username' => $punishment['creator_username'],
'remover_uuid' => $removerUuid,
'remover_username' => $punishment['remover_username'],
'removed_reason' => $punishment['removed_reason'],
'removed_at' => $removedAtDate,
]);

// TODO: Report and FireEvent accordingly if its Punish or Pardon event.

DB::commit();

// Forget Metrics Cache
Cache::forget('banwarden.public.metrics');

return $this->success(null, __('Punishment reported successfully.'));
} catch (\Exception $e) {
DB::rollBack();
\Log::error($e);

return $this->error(__('Failed to report punishment: :message', [
'message' => $e->getMessage(),
]), 'failed_to_report_punishment', 500);
}
}
}
Loading

0 comments on commit 8968821

Please sign in to comment.