Skip to content
Snippets Groups Projects
MarkController.php 12.2 KiB
Newer Older
Tibo's avatar
Tibo committed
<?php

namespace App\Http\Controllers;

use Cylab\Mark\Client;

use Illuminate\Support\Facades\Auth;
class MarkController extends Controller
{
    private function server() : Client
    {
        return Mark::get();
Tibo's avatar
Tibo committed
    }

Tibo's avatar
Tibo committed
    public function status()
    {
        $status = $this->server()->status();
        $status_history = $this->server()->history();
Tibo's avatar
Tibo committed

        $history_memory = $this->extractPoints($status_history, "memory_used");
        $history_load = $this->extractPoints($status_history, "load");

        $history_jobs_executed = $this->extractPoints($status_history, "executor_jobs_executed");
        $history_jobs_execution_rate = $this->computeExecutionRate($history_jobs_executed);

        $history_db_records = $this->extractPoints($status_history, "db_data_count");
        $history_db_records_rate = $this->computeExecutionRate($history_db_records);

        $history_db_evidences = $this->extractPoints($status_history, "db_evidence_count");
        $history_db_evidences_rate = $this->computeExecutionRate($history_db_evidences);
Tibo's avatar
Tibo committed

Tibo's avatar
Tibo committed
        return view("app.status", [
            "status" => $status,
            "history_memory" => $history_memory,
            "history_load" => $history_load,
            "history_jobs_execution_rate" => $history_jobs_execution_rate,
            "history_db_records_rate" => $history_db_records_rate,
            "history_db_evidences_rate" => $history_db_evidences_rate,
            "sources" => $sources]);
Tibo's avatar
Tibo committed
    }

    public function dbStatus()
    {
        $db_status = $this->server()->status();
        $summary = ["db.data.count" => $db_status["db.data.count"],
                    "db.data.size" => $db_status["db.data.size"],
                    "db.evidence.count" => $db_status["db.evidence.count"],
                    "db.evidence.size" => $db_status["db.evidence.size"]];

        $now = \Carbon\Carbon::now();

        $file_name = $now->toISOString() . "_db_status.json";
        $headers = array(
            "Content-type"        => "text/json",
            "Content-Disposition" => "attachment; filename=$file_name",
            "Pragma"              => "no-cache",
            "Cache-Control"       => "must-revalidate, post-check=0, pre-check=0",
            "Expires"             => "0"
        );

        $content = json_encode($summary);
        return response($content, 200, $headers);
    }

    public function lastData()
    {
        return view("app.lastdata", ["data" => $this->server()->findLastData()]);
    }

    public function lastEvidences()
    {
        return view(
Tibo's avatar
Tibo committed
            "app.lastevidences",
            ["evidences" => $this->server()->findLastEvidences()]
        );
Tibo's avatar
Tibo committed
    public function pause()
    {
Tibo's avatar
Tibo committed
        return redirect(action('MarkController@status'));
    }

Tibo's avatar
Tibo committed
    public function resume()
    {
Tibo's avatar
Tibo committed
        return redirect(action('MarkController@status'));
    }

Tibo's avatar
Tibo committed
    public function reload()
    {
Tibo's avatar
Tibo committed
        return redirect(action('MarkController@status'));
    }
Tibo's avatar
Tibo committed

    /**
     * Find
     * @param string $label
     * @return type the detector corresponding to this label.
     * Otherwize redirect to the detectors graph.
     */
    private function findDetector(string $label)
Tibo's avatar
Tibo committed
    {
        $detectors = $this->server()->activation();
        $detector = null;
        foreach ($detectors as $d) {
            if ($d->label == $label) {
        if ($detector === null) {
            session()->flash(
Tibo's avatar
Tibo committed
                'error',
                $label . ' is not a detector and does not produce a ranking'
            );
            abort(redirect(action('MarkController@rankingHome')));
Tibo's avatar
Tibo committed

        return $detector;
    }

    public function ranking(string $label)
    {

        $detector = $this->findDetector($label);
        $evidences = $this->server()->findEvidence($label);
Tibo's avatar
Tibo committed
        $now = \Carbon\Carbon::now();

Tibo's avatar
Tibo committed
        return view(
Tibo's avatar
Tibo committed
            "app.ranking",
            [
Tibo's avatar
Tibo committed
                    "label" => $label,
                    "evidences" => $evidences,
Tibo's avatar
Tibo committed
                    "detector" => $detector,
Tibo's avatar
Tibo committed
            "now" => $now]
        );
Tibo's avatar
Tibo committed
    }

    public function bubble(string $label)
    {
        return view('app.bubble', ["label" => $label]);
    }

    public function radar(string $label)
    {
        return view('app.radar', ["label" => $label]);
    }

    public function rankingCSV(string $label)
    {
        $evidences = $this->server()->findEvidence($label);
        $now = \Carbon\Carbon::now();

        $file_name = $now->toISOString() . "_$label.csv";
        $headers = array(
            "Content-type"        => "text/csv",
            "Content-Disposition" => "attachment; filename=$file_name",
            "Pragma"              => "no-cache",
            "Cache-Control"       => "must-revalidate, post-check=0, pre-check=0",
            "Expires"             => "0"
        );

        $columns = ['id', 'subject', 'score', 'time'];

Tibo's avatar
Tibo committed
        $callback = function () use ($evidences, $columns) {
            $file = fopen('php://output', 'w');
            fputcsv($file, $columns);

            foreach ($evidences as $ev) {
                fputcsv($file, [
                    $ev->id,
                    $ev->subject(),
                    $ev->score,
                    $ev->time
                ]);
            }

            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    public function rankingJSON(string $label)
    {
        $evidences = $this->server()->findEvidence($label);
        $summary = [];
        foreach ($evidences as $ev) {
            $summary[] = [
                "id" => $ev->id,
                "subject" => $ev->subject,
                "score" => $ev->score,
                "time" => $ev->time
            ];
        }

        $now = \Carbon\Carbon::now();

        $file_name = $now->toISOString() . "_$label.json";
        $headers = array(
            "Content-type"        => "text/json",
            "Content-Disposition" => "attachment; filename=$file_name",
            "Pragma"              => "no-cache",
            "Cache-Control"       => "must-revalidate, post-check=0, pre-check=0",
            "Expires"             => "0"
        );

        $content = json_encode($summary);
        return response($content, 200, $headers);
    }

Tibo's avatar
Tibo committed
    public function rankingHome()
    {
Tibo's avatar
Tibo committed
        $activation_graph_elements = [];
        $detectors = $this->server()->activation();

        // nodes
        foreach ($detectors as $detector) {
            // node
            $activation_graph_elements[] = ["data" => ["id" => $detector->label]];
Tibo's avatar
Tibo committed

            // edges
            $sources = $this->findSources($detectors, $detector);
            foreach ($sources as $source) {
                $activation_graph_elements[] = ["data" => [
                    "id" => rand(),
                    "source" => $source,
                    "target" => $detector->label]];
            }

            if (count($sources) == 0) {
                // the trigger_label for this detector is a data source
                // => create node + edge
                $activation_graph_elements[] = ["data" => ["id" => $detector->trigger_label]];
                $activation_graph_elements[] = ["data" => [
                    "id" => rand(),
                    "source" => $detector->trigger_label,
                    "target" => $detector->label]];
            }
Tibo's avatar
Tibo committed
        }
Tibo's avatar
Tibo committed

Tibo's avatar
Tibo committed
        return view("app.detectors", ["activation_graph_elements" => $activation_graph_elements]);
Tibo's avatar
Tibo committed
    }

    public function dashboardHome()
    {
        $graph_elements = [];
        $detectors = $this->server()->activation();

        // detectors
        foreach ($detectors as $detector) {
            //$evidences = $this->rankingJSON($detector->label);
            // add the name of the agents and the evidences linked to it
            $graph_elements[] = ["name" => $detector->label];
        }

        return view("app.dashboard", ["graph_elements" => $graph_elements]);
    }

    private function findSources(array $all_detectors, $detector)
    {

        $pattern = '/' . $detector->trigger_label . '/';
        $sources = [];
        foreach ($all_detectors as $d) {
            if (preg_match($pattern, $d->label)) {
                $sources[] = $d->label;
            }
        }

        return $sources;
    }

Tibo's avatar
Tibo committed
    public function extractPoints(array $evidences, string $field) : array
    {
        $points = [];
        foreach ($evidences as $evidence) {
            // used by status history
            // this is dirty :-(
            // status history should return an array of objects
            if (is_array($evidence)) {
                $points[] = new \App\TimePoint(
Tibo's avatar
Tibo committed
                    $evidence["time"],
                    $evidence[$field]
                );
Tibo's avatar
Tibo committed
                    $evidence->time,
                    $evidence->$field
                );
Tibo's avatar
Tibo committed
    public function evidence(string $id)
    {
        $time_window = 3600; // in seconds

        $ev = $this->server()->findEvidenceById($id);
        $since = $ev->time - $time_window * 1000;
Tibo's avatar
Tibo committed

        $references = [];
            $references[] = $this->server()->findEvidenceById($id);
Tibo's avatar
Tibo committed
        }

        $history = $this->server()->findEvidenceSince($ev->label, $ev->subject, $since);
        $feedback = Feedback::findByReportId($ev->id);
Tibo's avatar
Tibo committed
        return view(
Tibo's avatar
Tibo committed
            'app.evidence',
            [
Tibo's avatar
Tibo committed
                    "evidence" => $ev,
                    "history" => $history,
Tibo's avatar
Tibo committed
                    "history_points" => $this->extractPoints($history, "score"),
                    "feedback" => $feedback,
                    "references" => $references]
Tibo's avatar
Tibo committed
        );
Tibo's avatar
Tibo committed
    }
    /**
     * Mark an evidence as false alarm (whitelist).
     * @param string $id
     */
    public function falseAlarm(string $id)
    {
        $feedback = new Feedback();
        $feedback->report_id = $id;
        $feedback->is_true_alert = false;
        $feedback->user_id = Auth::id();
        $feedback->save();

        return redirect(action('MarkController@evidence', ['id' => $id]));
    }

    /**
     * Mark an evidence as false alarm (whitelist).
     * @param string $id
     */
    public function trueDetection(string $id)
    {
        $feedback = new Feedback();
        $feedback->report_id = $id;
        $feedback->is_true_alert = true;
        $feedback->user_id = Auth::id();
        $feedback->save();

        return redirect(action('MarkController@evidence', ['id' => $id]));
    }

    public function evidenceData(string $id, $data_id)
    {
        $ev = $this->server()->findEvidenceById($id);
        $query = $ev->requests[$data_id];
        $data = $this->server()->findDataByQuery($query);

        return view('app.data', [
            "evidence" => $ev,
            "query" => $query,
            "data" => $data
        ]);
    }

    /**
     * Compute the number of jobs executed per minute.
     *
     * @param array $history_jobs_executed
     * @return array
     */
Tibo's avatar
Tibo committed
    private function computeExecutionRate(array $history_jobs_executed) : array
    {

        if (count($history_jobs_executed) < 2) {
            // not enough points to compute execution rate...
            return [];
        }

        $points = [];
        $last_point = $history_jobs_executed[0];

        foreach ($history_jobs_executed as $point) {
            $delta_t_minutes = ($point->t - $last_point->t) / 60000;

            // this point is less than a minute after the last computed point
            if ($delta_t_minutes < 1) {
            $delta_value = $point->y - $last_point->y;
            if ($delta_value < 0) {
                $delta_value = 0;
            }
            $points[] = new \App\TimePoint(
Tibo's avatar
Tibo committed
                $point->t,
                round($delta_value / $delta_t_minutes)
            );
            $last_point = $point;
Tibo's avatar
Tibo committed
}