diff --git a/app/Helpers/AdversaryMeter.php b/app/Helpers/AdversaryMeter.php index 93587b3..2e73eb9 100644 --- a/app/Helpers/AdversaryMeter.php +++ b/app/Helpers/AdversaryMeter.php @@ -19,11 +19,13 @@ public static function redirectUrl() public static function addAsset(string $team, User $user, string $asset): array { + // TODO : sink the CreateAsset event return self::addAsset2(self::apiKey(), $team, $user->email, $asset); } public static function removeAsset(string $team, User $user, string $asset): array { + // TODO : sink the DeleteAsset event return self::removeAsset2(self::apiKey(), $team, $user->email, $asset); } @@ -140,6 +142,14 @@ private static function findAnyAdversaryMeterApiToken(User $user): ?string return $userTmp->am_api_token; } } - return null; + + $token = $user->createToken('adversarymeter', ['']); + $plainTextToken = $token->plainTextToken; + $token = $token?->accessToken; + + $user->am_api_token = $plainTextToken; + $user->save(); + + return $plainTextToken; } } \ No newline at end of file diff --git a/app/Modules/AdversaryMeter/Events/CreateAsset.php b/app/Modules/AdversaryMeter/Events/CreateAsset.php index fb1711d..fe3440b 100644 --- a/app/Modules/AdversaryMeter/Events/CreateAsset.php +++ b/app/Modules/AdversaryMeter/Events/CreateAsset.php @@ -2,6 +2,7 @@ namespace App\Modules\AdversaryMeter\Events; +use App\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Foundation\Events\Dispatchable; @@ -11,10 +12,12 @@ class CreateAsset { use Dispatchable, InteractsWithSockets, SerializesModels; + public User $user; public string $asset; - public function __construct(string $asset) + public function __construct(User $user, string $asset) { + $this->user = $user; $this->asset = $asset; } diff --git a/app/Modules/AdversaryMeter/Events/DeleteAsset.php b/app/Modules/AdversaryMeter/Events/DeleteAsset.php index 40755b4..2b7f1fd 100644 --- a/app/Modules/AdversaryMeter/Events/DeleteAsset.php +++ b/app/Modules/AdversaryMeter/Events/DeleteAsset.php @@ -2,6 +2,7 @@ namespace App\Modules\AdversaryMeter\Events; +use App\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Foundation\Events\Dispatchable; @@ -11,10 +12,12 @@ class DeleteAsset { use Dispatchable, InteractsWithSockets, SerializesModels; + public User $user; public string $asset; - public function __construct(string $asset) + public function __construct(User $user, string $asset) { + $this->user = $user; $this->asset = $asset; } diff --git a/app/Modules/AdversaryMeter/Http/Controllers/AssetController.php b/app/Modules/AdversaryMeter/Http/Controllers/AssetController.php index c65341f..a6bbf07 100644 --- a/app/Modules/AdversaryMeter/Http/Controllers/AssetController.php +++ b/app/Modules/AdversaryMeter/Http/Controllers/AssetController.php @@ -5,6 +5,7 @@ use App\Modules\AdversaryMeter\Events\BeginPortsScan; use App\Modules\AdversaryMeter\Helpers\ApiUtils; use App\Modules\AdversaryMeter\Listeners\CreateAssetListener; +use App\Modules\AdversaryMeter\Listeners\DeleteAssetListener; use App\Modules\AdversaryMeter\Models\Alert; use App\Modules\AdversaryMeter\Models\Asset; use App\Modules\AdversaryMeter\Models\AssetTag; @@ -73,7 +74,7 @@ public function saveAsset(Request $request): array /** @var User $user */ $user = Auth::user(); - $obj = CreateAssetListener::execute($asset); + $obj = CreateAssetListener::execute($user, $asset); if (!$obj) { abort(500, "The asset could not be created : {$asset}"); @@ -340,7 +341,10 @@ public function deleteAsset(Asset $asset): void if ($asset->is_monitored) { abort(500, 'Deletion not allowed, asset is monitored.'); } - $asset->delete(); + + /** @var User $user */ + $user = Auth::user(); + DeleteAssetListener::execute($user, $asset); } public function restartScan(Asset $asset): array diff --git a/app/Modules/AdversaryMeter/Http/Controllers/HoneypotController.php b/app/Modules/AdversaryMeter/Http/Controllers/HoneypotController.php index 7c42639..545b37d 100644 --- a/app/Modules/AdversaryMeter/Http/Controllers/HoneypotController.php +++ b/app/Modules/AdversaryMeter/Http/Controllers/HoneypotController.php @@ -123,7 +123,7 @@ public function getVulnerabilitiesWithAssetInfo(?int $attackerId = null): array return Alert::select('alerts.*', 'assets.id AS asset_id') ->join('ports', 'ports.id', '=', 'alerts.port_id') ->join('scans', 'scans.id', '=', 'ports.scan_id') - ->join('assets', 'assets.cur_scan_id', '=', 'ports.ports_scan_id') + ->join('assets', 'assets.cur_scan_id', '=', 'scans.ports_scan_id') ->get() ->map(function (Alert $alert) use ($attackerId) { return [ @@ -207,14 +207,14 @@ public function attackerStats(Attacker $attacker): array public function getMostRecentEvent(?int $attackerId = null): array { if ($attackerId) { - return HoneypotEvent::query() + return Attacker::find($attackerId) + ->events() ->orderBy('timestamp', 'desc') ->limit(3) ->get() ->toArray(); } - return Attacker::find($attackerId) - ->events() + return HoneypotEvent::query() ->orderBy('timestamp', 'desc') ->limit(3) ->get() @@ -298,7 +298,7 @@ public function honeypotsStatus(): array }, 'dns_setup'); return [ - 'current_user' => 'unknown', + 'current_user' => Auth::user()->name, 'honeypots' => $honeypots, 'integration_status' => $honeypots->count() ? $leastAdvancedStatus : 'inactive' ]; @@ -386,7 +386,7 @@ public function getHashes(): array return AssetTagHash::all()->toArray(); } - public function createHash(Request $request): array + public function createHash(Request $request): AssetTagHash { $tag = $request->validate([ 'tag' => 'string|required', @@ -398,9 +398,8 @@ public function createHash(Request $request): array ]); } - public function deleteHash(string $hash): JsonResponse + public function deleteHash(AssetTagHash $hash): JsonResponse { - $hash = AssetTagHash::where('hash', $hash)->firstOrFail(); $hash->delete(); return response()->json(['message' => 'Hash successfully deleted']); } diff --git a/app/Modules/AdversaryMeter/Listeners/CreateAssetListener.php b/app/Modules/AdversaryMeter/Listeners/CreateAssetListener.php index 1f675f2..eeca8fb 100644 --- a/app/Modules/AdversaryMeter/Listeners/CreateAssetListener.php +++ b/app/Modules/AdversaryMeter/Listeners/CreateAssetListener.php @@ -9,11 +9,13 @@ use App\Modules\AdversaryMeter\Rules\IsValidAsset; use App\Modules\AdversaryMeter\Rules\IsValidDomain; use App\Modules\AdversaryMeter\Rules\IsValidIpAddress; +use App\User; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; class CreateAssetListener extends AbstractListener { - public static function execute(string $asset): ?Asset + public static function execute(User $user, string $asset): ?Asset { if (!IsValidAsset::test($asset)) { Log::error("Invalid asset : {$asset}"); @@ -26,6 +28,7 @@ public static function execute(string $asset): ?Asset } else { $assetType = AssetTypesEnum::RANGE; } + Auth::login($user); // otherwise the tenant will not be properly set return Asset::updateOrCreate( [ 'asset' => $asset, @@ -42,6 +45,6 @@ protected function handle2($event) if (!($event instanceof CreateAsset)) { throw new \Exception('Invalid event type!'); } - self::execute($event->asset); + self::execute($event->user, $event->asset); } } diff --git a/app/Modules/AdversaryMeter/Listeners/DeleteAssetListener.php b/app/Modules/AdversaryMeter/Listeners/DeleteAssetListener.php index 97da66b..34b3d95 100644 --- a/app/Modules/AdversaryMeter/Listeners/DeleteAssetListener.php +++ b/app/Modules/AdversaryMeter/Listeners/DeleteAssetListener.php @@ -9,11 +9,13 @@ use App\Modules\AdversaryMeter\Rules\IsValidAsset; use App\Modules\AdversaryMeter\Rules\IsValidDomain; use App\Modules\AdversaryMeter\Rules\IsValidIpAddress; +use App\User; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; class DeleteAssetListener extends AbstractListener { - public static function execute(string $asset): bool + public static function execute(User $user, string $asset): bool { if (!IsValidAsset::test($asset)) { Log::error("Invalid asset : {$asset}"); @@ -27,6 +29,7 @@ public static function execute(string $asset): bool $assetType = AssetTypesEnum::RANGE; } + Auth::login($user); // otherwise the tenant will not be properly set Asset::where('asset', $asset)->where('type', $assetType)->delete(); return true; } @@ -36,6 +39,6 @@ protected function handle2($event) if (!($event instanceof DeleteAsset)) { throw new \Exception('Invalid event type!'); } - self::execute($event->asset); + self::execute($event->user, $event->asset); } } diff --git a/app/Modules/AdversaryMeter/Models/Asset.php b/app/Modules/AdversaryMeter/Models/Asset.php index 80b440d..69d948f 100644 --- a/app/Modules/AdversaryMeter/Models/Asset.php +++ b/app/Modules/AdversaryMeter/Models/Asset.php @@ -3,7 +3,7 @@ namespace App\Modules\AdversaryMeter\Models; use App\Modules\AdversaryMeter\Enums\AssetTypesEnum; -use App\Traits\HasTenant; +use App\Modules\AdversaryMeter\Traits\HasTenant; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; diff --git a/app/Modules/AdversaryMeter/Models/AssetTag.php b/app/Modules/AdversaryMeter/Models/AssetTag.php index 9b27b87..4c6acb4 100644 --- a/app/Modules/AdversaryMeter/Models/AssetTag.php +++ b/app/Modules/AdversaryMeter/Models/AssetTag.php @@ -2,7 +2,7 @@ namespace App\Modules\AdversaryMeter\Models; -use App\Traits\HasTenant; +use App\Modules\AdversaryMeter\Traits\HasTenant; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; diff --git a/app/Modules/AdversaryMeter/Models/AssetTagHash.php b/app/Modules/AdversaryMeter/Models/AssetTagHash.php index 1bd66bf..a6170b5 100644 --- a/app/Modules/AdversaryMeter/Models/AssetTagHash.php +++ b/app/Modules/AdversaryMeter/Models/AssetTagHash.php @@ -2,7 +2,7 @@ namespace App\Modules\AdversaryMeter\Models; -use App\Traits\HasTenant; +use App\Modules\AdversaryMeter\Traits\HasTenant; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; diff --git a/app/Modules/AdversaryMeter/Models/HiddenAlert.php b/app/Modules/AdversaryMeter/Models/HiddenAlert.php index eafa1a0..2b93b26 100644 --- a/app/Modules/AdversaryMeter/Models/HiddenAlert.php +++ b/app/Modules/AdversaryMeter/Models/HiddenAlert.php @@ -2,12 +2,13 @@ namespace App\Modules\AdversaryMeter\Models; +use App\Modules\AdversaryMeter\Traits\HasTenant; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class HiddenAlert extends Model { - use HasFactory; + use HasFactory, HasTenant; protected $table = 'hidden_alerts'; protected $connection = 'mysql_am'; diff --git a/app/Modules/AdversaryMeter/Models/Honeypot.php b/app/Modules/AdversaryMeter/Models/Honeypot.php index 0d96a21..30c1406 100644 --- a/app/Modules/AdversaryMeter/Models/Honeypot.php +++ b/app/Modules/AdversaryMeter/Models/Honeypot.php @@ -5,7 +5,7 @@ use App\Modules\AdversaryMeter\Enums\HoneypotCloudProvidersEnum; use App\Modules\AdversaryMeter\Enums\HoneypotCloudSensorsEnum; use App\Modules\AdversaryMeter\Enums\HoneypotStatusesEnum; -use App\Traits\HasTenant; +use App\Modules\AdversaryMeter\Traits\HasTenant; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; diff --git a/app/Modules/AdversaryMeter/Observers/AssetObserver.php b/app/Modules/AdversaryMeter/Observers/AssetObserver.php index 53dabe6..68a5594 100644 --- a/app/Modules/AdversaryMeter/Observers/AssetObserver.php +++ b/app/Modules/AdversaryMeter/Observers/AssetObserver.php @@ -2,7 +2,7 @@ namespace App\Modules\AdversaryMeter\Observers; -use App\Traits\IsTenantAware; +use App\Modules\AdversaryMeter\Traits\IsTenantAware; class AssetObserver { diff --git a/app/Modules/AdversaryMeter/Observers/AssetTagHashObserver.php b/app/Modules/AdversaryMeter/Observers/AssetTagHashObserver.php index fe470f2..c26cadb 100644 --- a/app/Modules/AdversaryMeter/Observers/AssetTagHashObserver.php +++ b/app/Modules/AdversaryMeter/Observers/AssetTagHashObserver.php @@ -2,7 +2,7 @@ namespace App\Modules\AdversaryMeter\Observers; -use App\Traits\IsTenantAware; +use App\Modules\AdversaryMeter\Traits\IsTenantAware; class AssetTagHashObserver { diff --git a/app/Modules/AdversaryMeter/Observers/AssetTagObserver.php b/app/Modules/AdversaryMeter/Observers/AssetTagObserver.php index e2b1843..fc62c05 100644 --- a/app/Modules/AdversaryMeter/Observers/AssetTagObserver.php +++ b/app/Modules/AdversaryMeter/Observers/AssetTagObserver.php @@ -2,7 +2,7 @@ namespace App\Modules\AdversaryMeter\Observers; -use App\Traits\IsTenantAware; +use App\Modules\AdversaryMeter\Traits\IsTenantAware; class AssetTagObserver { diff --git a/app/Modules/AdversaryMeter/Observers/HiddenAlert.php b/app/Modules/AdversaryMeter/Observers/HiddenAlert.php new file mode 100644 index 0000000..b6b4eea --- /dev/null +++ b/app/Modules/AdversaryMeter/Observers/HiddenAlert.php @@ -0,0 +1,10 @@ +tenant_id; + + if ($tenantId) { + + $customerId = $user->customer_id; + + if ($customerId) { + $users = User::select('id') + ->whereRaw("(tenant_id IS NULL OR tenant_id = {$tenantId})") + ->whereRaw("(customer_id IS NULL OR customer_id = {$customerId})") + ->get(); + } else { + $users = User::select('id') + ->whereRaw("(tenant_id IS NULL OR tenant_id = {$tenantId})") + ->get(); + } + + $builder->whereNull('created_by') + ->orWhereIn('created_by', $users); + } + }); + } + + public function createdBy(): User + { + return User::where('id', $this->created_by)->firstOrFail(); + } + + public function tenant(): ?Tenant + { + return $this->createdBy()->tenant(); + } +} \ No newline at end of file diff --git a/app/Modules/AdversaryMeter/Traits/IsTenantAware.php b/app/Modules/AdversaryMeter/Traits/IsTenantAware.php new file mode 100644 index 0000000..e1082e3 --- /dev/null +++ b/app/Modules/AdversaryMeter/Traits/IsTenantAware.php @@ -0,0 +1,50 @@ +tenant_id || $user->tenant_id === optional($model->tenant())->id) { + return true; + } + return false; + } + + public function updating(Model $model) + { + $user = Auth::user(); + + if (!$model->created_by) { + $model->created_by = $user?->id; + return true; + } + if (!$user || !$user->tenant_id || $user->tenant_id === optional($model->tenant())->id) { + return true; + } + return false; + } + + public function creating(Model $model) + { + $user = Auth::user(); + + if (!$model->created_by) { + $model->created_by = $user?->id; + return true; + } + if (!$user || !$user->tenant_id || $user->tenant_id === optional($model->tenant())->id) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/app/Modules/AdversaryMeter/api.php b/app/Modules/AdversaryMeter/api.php index aa4f13c..a0e9ca7 100644 --- a/app/Modules/AdversaryMeter/api.php +++ b/app/Modules/AdversaryMeter/api.php @@ -55,7 +55,7 @@ Route::get('assets/tags', 'HoneypotController@assetTags'); Route::get('hashes', 'HoneypotController@getHashes'); Route::post('hashes', 'HoneypotController@createHash'); - Route::delete('hashes/{hash}', 'HoneypotController@deleteHash'); + Route::delete('hashes/{hashId}', 'HoneypotController@deleteHash'); Route::post('hidden-alerts', 'HoneypotController@createHiddenAlert'); Route::delete('hidden-alerts/{hiddenAlertId}', 'HoneypotController@deleteHiddenAlert'); Route::post('honeypots', 'HoneypotController@postHoneypots'); diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index b20ef0d..32674e8 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -73,7 +73,7 @@ protected function mapApiRoutes() ->middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api.php')); - Route::prefix('am/api') + Route::prefix('am/api/v2') ->middleware('api') ->namespace('App\Modules\AdversaryMeter\Http\Controllers') ->group(base_path('app/Modules/AdversaryMeter/api.php')); diff --git a/public/adversary_meter/src/conf.js b/public/adversary_meter/src/conf.js index 4c5d4c6..7c7c91c 100644 --- a/public/adversary_meter/src/conf.js +++ b/public/adversary_meter/src/conf.js @@ -1,7 +1,7 @@ 'use strict' const conf = { - API_BASE_URL: "https://sentinel.computablefacts.com", + API_BASE_URL: "http://127.0.0.1:8080", ENV: 'PROD', SKIP_HONEYPOT: true } \ No newline at end of file diff --git a/public/adversary_meter/src/js/_datastore/api.js b/public/adversary_meter/src/js/_datastore/api.js index 4d681ba..c5d9a86 100644 --- a/public/adversary_meter/src/js/_datastore/api.js +++ b/public/adversary_meter/src/js/_datastore/api.js @@ -16,6 +16,7 @@ if (httpClient.getBaseUrl() === '') { httpClient.init(conf.API_BASE_URL); } +/** @deprecated */ export function urlStartDiscussion(vulnId) { return httpClient.getBaseUrl() + `/api/v2/adversary/start-discussion/${vulnId}?api_token=${httpClient.getToken()}`; } @@ -26,7 +27,7 @@ export async function whoAmI() { export async function apiCall(method, url, params = {}, body = null) { - let fullUrl = httpClient.getBaseUrl() + "/" + url; + let fullUrl = httpClient.getBaseUrl() + "/am/" + url; if (method.toUpperCase() === "GET" && Object.keys(params).length > 0) { const queryParams = new URLSearchParams(params).toString(); diff --git a/public/adversary_meter/src/js/_datastore/hash.js b/public/adversary_meter/src/js/_datastore/hash.js index 77c9f00..652c240 100644 --- a/public/adversary_meter/src/js/_datastore/hash.js +++ b/public/adversary_meter/src/js/_datastore/hash.js @@ -4,8 +4,8 @@ export class HashObject { constructor(hash) { this.id = hash.id; - this.hash = hash.value_0; - this.tag = hash.value_1; - this.views = hash.value_2; + this.hash = hash.hash; + this.tag = hash.tag; + this.views = hash.views; } } diff --git a/routes/api.php b/routes/api.php index 2a9252f..1ff5f2a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,6 +1,7 @@ get('/user', function (Request $request) { - return \Illuminate\Support\Facades\Auth::user(); +Route::middleware('auth:api')->get('/v2/public/whoami', function (Request $request) { + return Auth::user(); });