Skip to content

Commit

Permalink
fix permissions for banwarden apis
Browse files Browse the repository at this point in the history
  • Loading branch information
Xinecraft committed Oct 25, 2024
1 parent 8968821 commit 3d27171
Show file tree
Hide file tree
Showing 10 changed files with 371 additions and 53 deletions.
37 changes: 37 additions & 0 deletions app/Events/BanWardenPlayerPardoned.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Events;

use App\Models\PlayerPunishment;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class BanWardenPlayerPardoned
{
use Dispatchable, InteractsWithSockets, SerializesModels;

/**
* Create a new event instance.
*/
public function __construct(public PlayerPunishment $punishment)
{
//
}

/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
37 changes: 37 additions & 0 deletions app/Events/BanWardenPlayerPunished.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Events;

use App\Models\PlayerPunishment;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class BanWardenPlayerPunished
{
use Dispatchable, InteractsWithSockets, SerializesModels;

/**
* Create a new event instance.
*/
public function __construct(public PlayerPunishment $punishment)
{
//
}

/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
30 changes: 21 additions & 9 deletions app/Http/Controllers/Api/ApiBanWardenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace App\Http\Controllers\Api;

use App\Events\BanWardenPlayerPardoned;
use App\Events\BanWardenPlayerPunished;
use App\Jobs\GeneratePunishmentInsightsJob;
use App\Models\Player;
use App\Models\PlayerPunishment;
use App\Models\Server;
Expand Down Expand Up @@ -40,9 +43,10 @@ public function postSyncPunishments(Request $request, GeolocationService $geoloc
'data.punishments.*.from_event' => 'required|in:punish,pardon,sync',
]);

$banwardenEnabledInConfig = config('minetrax.banwarden_enabled');
$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);
if (!$banwardenEnabledInConfig || !$server->settings['is_banwarden_enabled']) {
return $this->error(__('BanWarden is disabled globally or on this server.'), 'banwarden_disabled', 403);
}

DB::beginTransaction();
Expand Down Expand Up @@ -150,12 +154,12 @@ public function postReportPunishment(Request $request, GeolocationService $geolo
'data.from_event' => 'required|in:punish,pardon,sync',
]);

$banwardenEnabledInConfig = config('minetrax.banwarden_enabled');
$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);
if (!$banwardenEnabledInConfig || !$server->settings['is_banwarden_enabled']) {
return $this->error(__('BanWarden is disabled globally or on this server.'), 'banwarden_disabled', 403);
}

DB::beginTransaction();
try {
$punishment = $request->input('data');
$playerUuid = Str::isUuid($punishment['uuid']) ? $punishment['uuid'] : null;
Expand Down Expand Up @@ -192,7 +196,7 @@ public function postReportPunishment(Request $request, GeolocationService $geolo
$forGeoIp = str_replace(['%', '*'], '0', $punishment['ip_address']);
$countryId = $geolocationService->getCountryIdFromIP($forGeoIp);

PlayerPunishment::updateOrCreate([
$punishment = PlayerPunishment::updateOrCreate([
'type' => $punishment['type'],
'plugin_punishment_id' => $punishment['plugin_punishment_id'],
'plugin_name' => $punishment['plugin_name'],
Expand All @@ -218,16 +222,24 @@ public function postReportPunishment(Request $request, GeolocationService $geolo
'removed_at' => $removedAtDate,
]);

// TODO: Report and FireEvent accordingly if its Punish or Pardon event.
// Dispatch Events
if ($punishment->from_event == 'punish') {
BanWardenPlayerPunished::dispatch($punishment);
} else if ($punishment->from_event == 'pardon') {
BanWardenPlayerPardoned::dispatch($punishment);
}

DB::commit();
// AI Insights
$insightEnabled = config('minetrax.banwarden_ai_insights_enabled');
if ($insightEnabled && !$punishment->insights) {
GeneratePunishmentInsightsJob::dispatch($punishment);
}

// 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', [
Expand Down
69 changes: 53 additions & 16 deletions app/Http/Controllers/BanWardenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\QueryBuilder;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Gate;

// TODO: Remove all critical data from the response.
class BanWardenController extends Controller
{
public function index()
{
$this->authorize('viewAny', PlayerPunishment::class);

$perPage = request()->input('perPage', 10);
if ($perPage > 100) {
$perPage = 100;
Expand Down Expand Up @@ -95,8 +97,11 @@ public function index()
]);
}

public function show(PlayerPunishment $playerPunishment)
public function show(PlayerPunishment $playerPunishment, Request $request)
{
$this->authorize('view', $playerPunishment);
$canViewCritical = Gate::allows('viewCritical', $playerPunishment);

$playerPunishment->load([
'country:id,name,iso_code',
'victimPlayer:id,uuid,username,skin_texture_id',
Expand All @@ -110,15 +115,31 @@ public function show(PlayerPunishment $playerPunishment)
GeneratePunishmentInsightsJob::dispatch($playerPunishment);
}

// return $responseProps;
$playerPunishment->victimPlayer?->append('render_url');
return Inertia::render('BanWarden/ShowPunishment', [
$playerPunishment->makeVisibleIf(
$canViewCritical,
[
'ip_address',
'plugin_punishment_id',
'origin_server_name',
]
);
$response = [
'punishment' => $playerPunishment,
]);
'permissions' => [
'canViewSessions' => Gate::allows('viewAnyIntel', Player::class),
'canViewAlts' => Gate::allows('viewAlts', $playerPunishment),
'canViewCritical' => $canViewCritical,
],
];
return Inertia::render('BanWarden/ShowPunishment', $response);
}

public function indexLastPunishments(PlayerPunishment $playerPunishment)
{
$this->authorize('view', $playerPunishment);
$canViewCritical = Gate::allows('viewCritical', $playerPunishment);

$perPage = request()->query('perPage', 10);
if ($perPage > 100) {
$perPage = 100;
Expand All @@ -134,7 +155,12 @@ public function indexLastPunishments(PlayerPunishment $playerPunishment)
->where('uuid', $playerPunishment->uuid)
->where('id', '!=', $playerPunishment->id)
->orderByDesc('start_at')
->simplePaginate($perPage);
->simplePaginate($perPage)
->through(fn($punishment) => $punishment->makeVisibleIf($canViewCritical, [
'ip_address',
'plugin_punishment_id',
'origin_server_name',
]));
} else {
$lastPunishments = PlayerPunishment::with([
'country:id,name,iso_code',
Expand All @@ -145,14 +171,22 @@ public function indexLastPunishments(PlayerPunishment $playerPunishment)
->where('ip_address', 'LIKE', $playerPunishment->ip_address)
->where('id', '!=', $playerPunishment->id)
->orderByDesc('start_at')
->simplePaginate($perPage);
->simplePaginate($perPage)
->through(fn($punishment) => $punishment->makeVisibleIf($canViewCritical, [
'ip_address',
'plugin_punishment_id',
'origin_server_name',
]));
}

return $lastPunishments;
}

public function indexLastSessions(PlayerPunishment $playerPunishment)
{
$this->authorize('viewAnyIntel', Player::class);
$canViewCritical = Gate::allows('viewCritical', $playerPunishment);

$perPage = request()->query('perPage', 5);
if ($perPage > 100) {
$perPage = 100;
Expand All @@ -164,30 +198,35 @@ public function indexLastSessions(PlayerPunishment $playerPunishment)
->where('session_started_at', '<=', $playerPunishment->start_at)
->orderByDesc('session_started_at')
->simplePaginate($perPage)
->through(function ($session) {
return $session->makeVisible('player_ip_address');
});
->through(fn($session) => $session->makeVisibleIf($canViewCritical, 'player_ip_address'));
} else {
$pastSessions = MinecraftPlayerSession::with(['country:id,name,iso_code', 'server:id,name'])
->where('player_ip_address', 'LIKE', $playerPunishment->ip_address)
->where('session_started_at', '<=', $playerPunishment->start_at)
->orderByDesc('session_started_at')
->simplePaginate($perPage)
->through(function ($session) {
return $session->makeVisible('player_ip_address');
});
->through(fn($session) => $session->makeVisibleIf($canViewCritical, 'player_ip_address'));
}

return $pastSessions;
}

public function indexAlts(PlayerPunishment $playerPunishment)
{
$this->authorize('viewAlts', $playerPunishment);
$canViewCritical = Gate::allows('viewCritical', $playerPunishment);

$perPage = request()->query('perPage', 5);
if ($perPage > 100) {
$perPage = 100;
}

if (!$playerPunishment->ip_address) {
return (object) [
'data' => [],
];
}

$firstTwoOctets = explode('.', $playerPunishment->ip_address);
$firstTwoOctets = $firstTwoOctets[0] . '.' . $firstTwoOctets[1] . '.%';
$altUuids = MinecraftPlayerSession::distinct()->select('player_uuid')
Expand All @@ -200,9 +239,7 @@ public function indexAlts(PlayerPunishment $playerPunishment)
->withCount('punishments')
->orderByDesc('last_seen_at')
->simplePaginate($perPage)
->through(function ($player) {
return $player->makeVisible('ip_address');
});
->through(fn($player) => $player->makeVisibleIf($canViewCritical, 'ip_address'));

return $players;
}
Expand Down
42 changes: 27 additions & 15 deletions app/Jobs/GeneratePunishmentInsightsJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,25 @@ public function handle(OpenAiService $openAiService): void
$lastSessionsJsonString = json_encode($pastSessions);

// Possible Alts
$firstTwoOctets = explode('.', $this->punishment->ip_address);
$firstTwoOctets = $firstTwoOctets[0] . '.' . $firstTwoOctets[1] . '.%';
$altUuids = MinecraftPlayerSession::distinct()->select('player_uuid')
->where('player_uuid', '!=', $this->punishment->uuid)
->where('player_ip_address', 'LIKE', $firstTwoOctets)
->pluck('player_uuid');
$players = Player::select(['id', 'uuid', 'username', 'skin_texture_id', 'first_seen_at', 'last_seen_at', 'country_id', 'ip_address', 'play_time'])
->whereIn('uuid', $altUuids)
->with('country:id,name,iso_code')
->withCount('punishments')
->orderByDesc('last_seen_at')
->limit(10)
->get()
->makeVisible('ip_address');
$possibleAltsJsonString = json_encode($players);
if (!$this->punishment->ip_address) {
$altPlayers = [];
} else {
$firstTwoOctets = explode('.', $this->punishment->ip_address);
$firstTwoOctets = $firstTwoOctets[0] . '.' . $firstTwoOctets[1] . '.%';
$altUuids = MinecraftPlayerSession::distinct()->select('player_uuid')
->where('player_uuid', '!=', $this->punishment->uuid)
->where('player_ip_address', 'LIKE', $firstTwoOctets)
->pluck('player_uuid');
$altPlayers = Player::select(['id', 'uuid', 'username', 'skin_texture_id', 'first_seen_at', 'last_seen_at', 'country_id', 'ip_address', 'play_time'])
->whereIn('uuid', $altUuids)
->with('country:id,name,iso_code')
->withCount('punishments')
->orderByDesc('last_seen_at')
->limit(10)
->get()
->makeVisible('ip_address');
}
$possibleAltsJsonString = json_encode($altPlayers);

$systemPrompt = view('gptprompts.punishment-insights');
$question = <<<QUESTION
Expand Down Expand Up @@ -153,4 +157,12 @@ public function handle(OpenAiService $openAiService): void
],
]);
}

// on failure, set insights to null
public function failed(): void
{
$this->punishment->update([
'insights' => null,
]);
}
}
15 changes: 13 additions & 2 deletions app/Models/PlayerPunishment.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
use App\Enums\PlayerPunishmentType;
use App\Traits\HasCommentsTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class PlayerPunishment extends BaseModel
class PlayerPunishment extends BaseModel implements HasMedia
{
use HasFactory, HasCommentsTrait;
use HasFactory, HasCommentsTrait, InteractsWithMedia;

protected $casts = [
'type' => PlayerPunishmentType::class,
Expand All @@ -27,6 +29,11 @@ class PlayerPunishment extends BaseModel

protected $hidden = [
'ip_address',
'plugin_name',
'plugin_punishment_id',
'meta',
'origin_server_name',
'origin_server_id',
];

public function scopeStatus($query, $status)
Expand Down Expand Up @@ -57,6 +64,10 @@ public function getIsActiveAttribute()

public function getMaskedIpAddressAttribute()
{
$hideCounty = config('minetrax.hide_country_for_privacy');
if ($hideCounty) {
return 'xx.xx.xx.xx';
}
return preg_replace('/(\d{1,3})\.\d{1,3}\.\d{1,3}\.\d{1,3}/', '$1.xx.xx.xx', $this->ip_address);
}

Expand Down
Loading

0 comments on commit 3d27171

Please sign in to comment.