<?php
/**
 * File: search.php
 * Author: Ryan Prather <ryan.prather@cyberperspectives.com>
 * Purpose: Contain all search/filtering functionality within Sagacity
 * Created: May 24, 2017
 *
 * Copyright 2017: Cyber Perspective, LLC, All rights reserved
 * Released under the Apache v2.0 License
 *
 * See license.txt for details
 *
 * Change Log:
 *  - May 24, 2017 - File created
 *  - May 26, 2017 - Couple bug fixes
 *  - Jul 13, 2017 - Fixed a couple minor display bugs
 *  - Dec 27, 2017 - Syntax updates
 *  - May 10, 2018 - Fixed bug #405, probably other bugs with other types
 *  - May 31, 2018 - Bug fixes
 */
include_once 'config.inc';
include_once 'helper.inc';
include_once 'database.inc';

$db = new db();

$type   = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING, FILTER_NULL_ON_FAILURE);
$q      = filter_input(INPUT_POST, 'q', FILTER_SANITIZE_STRING, FILTER_NULL_ON_FAILURE);
$start  = filter_input(INPUT_POST, 'start', FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
$len    = filter_input(INPUT_POST, 'length', FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
$draw   = filter_input(INPUT_POST, 'draw', FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
$filter = filter_input(INPUT_POST, 'search', FILTER_SANITIZE_STRING, FILTER_REQUIRE_ARRAY);

$where = [];
$op    = '=';
$field = null;
$ret   = null;

if (empty($q)) {
    print header(JSON) . json_encode(null);
    die;
}

if (strpos($q, "%") !== false) {
    $op = LIKE;
    $q  = "'$q'";
}

if ($type == 'stig' || $type == 'vms' || $type == 'ia' || $type == 'nessus') {
    if ($type == 'stig') {
        $field = '`STIG_ID`';
    }
    elseif ($type == 'vms') {
        $field = '`VMS_ID`';
    }
    elseif ($type == 'ia') {
        $field = '`IA_Controls`';
    }
    elseif ($type == 'nessus') {
        $field = '`Nessus_ID`';
    }

    if (!is_null($field)) {
        $where[] = [
            'field' => $field,
            'op'    => $op,
            'value' => $q
        ];
    }

    if (!empty($filter['value'])) {
        $where[] = [
            'field'      => 'pdi.STIG_ID',
            'op'         => LIKE,
            'value'      => "'%{$filter['value']}%'",
            'open-paren' => true,
            'sql_op'     => 'AND'
        ];
        $where[] = [
            'field'  => 'pdi.VMS_ID',
            'op'     => LIKE,
            'value'  => "'%{$filter['value']}%'",
            'sql_op' => 'OR'
        ];
        $where[] = [
            'field'  => 'pdi.IA_Controls',
            'op'     => LIKE,
            'value'  => "'%{$filter['value']}%'",
            'sql_op' => 'OR'
        ];
        $where[] = [
            'field'  => 'pdi.Short_Title',
            'op'     => LIKE,
            'value'  => "'%{$filter['value']}%'",
            'sql_op' => 'OR'
        ];
        $where[] = [
            'field'  => 'pdi.Description',
            'op'     => LIKE,
            'value'  => "'%{$filter['value']}%'",
            'sql_op' => 'OR'
        ];
        $where[] = [
            'field'       => 'lu.check_contents',
            'op'          => LIKE,
            'value'       => "'%{$filter['value']}%'",
            'sql_op'      => 'OR',
            'close-paren' => true
        ];
    }

    $db->help->select_count("sagacity.pdi", $where, [
        'table_joins' => [
            "LEFT JOIN sagacity.pdi_checklist_lookup lu ON pdi.pdi_id = lu.pdi_id",
            "LEFT JOIN sagacity.checklist chk ON chk.id = lu.checklist_id"
        ]
    ]);
    $count = $db->help->execute();

    $ret = [
        'columns'         => [
            ['title' => 'STIG ID', 'data' => 'stig_id'],
            ['title' => 'VMS ID', 'data' => 'vms_id'],
            ['title' => 'Checklist Name', 'data' => 'name'],
            ['title' => 'Type', 'data' => 'type'],
            ['title' => 'PDI', 'data' => 'pdi_id'],
            ['title' => 'File Name', 'data' => 'file']
        ],
        'draw'            => $draw,
        'recordsTotal'    => $count,
        'recordsFiltered' => $count,
        'data'            => []
    ];

    $db->help->select("sagacity.pdi", null, $where, [
        'table_joins' => [
            "LEFT JOIN sagacity.pdi_checklist_lookup lu ON pdi.pdi_id = lu.pdi_id",
            "LEFT JOIN sagacity.checklist chk ON chk.id = lu.checklist_id"
        ],
        'limit'       => $len,
        'start'       => $start
    ]);
    $rows = $db->help->execute();
    if (is_array($rows) && count($rows) && isset($rows['STIG_ID'])) {
        $rows = [0 => $rows];
    }

    if (is_array($rows) && count($rows) && isset($rows[0])) {
        foreach ($rows as $row) {
            $ret['data'][] = [
                'stig_id' => $row['STIG_ID'],
                'vms_id'  => $row['VMS_ID'],
                'name'    => $row['name'],
                'type'    => $row['type'],
                'pdi_id'  => $row['pdi_id'],
                'file'    => $row['file_name']
            ];
        }
    }
}
elseif ($type == 'cve') {
    $where[] = [
        'field' => 'db.cve_id',
        'op'    => $op,
        'value' => $q
    ];

    if (!empty($filter['value'])) {
        $where[] = [
            'field'      => 'status',
            'op'         => LIKE,
            'value'      => "'%{$filter['value']}%'",
            'sql_op'     => 'AND',
            'open-paren' => true
        ];
        $where[] = [
            'field'       => 'desc',
            'op'          => LIKE,
            'value'       => "'%{$filter['value']}%'",
            'sql_op'      => 'OR',
            'close-paren' => true
        ];
    }

    $db->help->select_count("sagacity.cve_db db", $where, [
        'table_joins' => [
            "LEFT JOIN sagacity.cve ON db.cve_id = cve.cve_id"
        ]
    ]);
    $count = $db->help->execute();

    $ret = [
        'columns'         => [
            ['title' => 'PDI ID', 'data' => 'pdi_id'],
            ['title' => 'CVE ID', 'data' => 'cve_id'],
            ['title' => 'Description', 'data' => 'desc'],
            ['title' => 'Status', 'data' => 'status'],
            ['title' => 'References', 'data' => 'ref']
        ],
        'draw'            => $draw,
        'recordsTotal'    => $count,
        'recordsFiltered' => $count,
        'data'            => []
    ];

    $db->help->select("sagacity.cve_db db", ['db.cve_id', 'cve.pdi_id', 'db.seq', 'db.status', 'db.desc'], $where, [
        'table_joins' => [
            "LEFT JOIN sagacity.cve ON db.cve_id = cve.cve_id"
        ],
        'limit'       => $len,
        'start'       => $start
    ]);
    $rows = $db->help->execute();
    if (is_array($rows) && count($rows) && isset($rows['cve_id'])) {
        $rows = [0 => $rows];
    }

    if (is_array($rows) && count($rows) && isset($rows[0])) {
        foreach ($rows as $row) {
            $references = null;
            $db->help->select("sagacity.cve_references", ['source', 'url'], [
                [
                    'field' => 'cve_seq',
                    'op'    => '=',
                    'value' => $row['cve_id']
                ],
                [
                    'field'  => 'url',
                    'op'     => '!=',
                    'value'  => '',
                    'sql_op' => 'AND'
                ]
                ], [
                'group' => 'source'
            ]);

            $refs = $db->help->execute();
            if (is_array($refs) && count($refs) && isset($refs['source'])) {
                $refs = [0 => $refs];
            }

            if (is_array($refs) && count($refs) && isset($refs[0])) {
                foreach ($refs as $ref) {
                    $references .= "<a href='{$ref['url']}' target='_blank'>{$ref['source']}</a> ";
                }
            }

            $ret['data'][] = [
                'pdi_id' => "<a href='#' onclick='javascript:open_pdi(\"{$row['pdi_id']}\");'>{$row['pdi_id']}</a>",
                'cve_id' => $row['cve_id'],
                'desc'   => $row['desc'],
                'status' => $row['status'],
                'ref'    => $references
            ];
        }
    }
}
elseif ($type == 'cpe') {
    $where[] = [
        'field' => 'cpe',
        'op'    => $op,
        'value' => $q
    ];

    if (!empty($filter['search'])) {
        $where[] = [
            'field'  => 'cpe',
            'op'     => LIKE,
            'value'  => $filter['search'],
            'sql_op' => 'OR'
        ];
    }

    $db->help->select_count("sagacity.software", $where);
    $count = $db->help->execute();

    $ret = [
        'columns'         => [
            ['title' => 'Man', 'data' => 'man'],
            ['title' => 'Name', 'data' => 'name'],
            ['title' => 'Ver', 'data' => 'ver'],
            ['title' => 'CPE', 'data' => 'cpe'],
            ['title' => 'String', 'data' => 'sw_string']
        ],
        'draw'            => $draw,
        'recordsTotal'    => $count,
        'recordsFiltered' => $count,
        'data'            => []
    ];

    $db->help->select("sagacity.software", null, $where);
    $rows = $db->help->execute();

    if (is_array($rows) && count($rows) && isset($rows['cpe'])) {
        $rows = [0 => $rows];
    }

    if (is_array($rows) && count($rows) && isset($rows[0])) {
        foreach ($rows as $row) {
            list($cpe, $type, $man, $name, $ver) = explode(":", $row['cpe']);
            $ret['data'][] = [
                'man'       => ucwords($man),
                'name'      => ucwords($name),
                'ver'       => $ver,
                'cpe'       => $row['cpe'],
                'sw_string' => $row['sw_string']
            ];
        }
    }
}
elseif ($type == 'iavm') {
    $where[] = [
        'field' => 'iavmNoticeNumber',
        'op'    => $op,
        'value' => $q
    ];

    $db->help->select_count("sagacity.iavm_notices", $where);
    $count = $db->help->execute();

    $ret = [
        'columns'         => [
            ['title' => 'PDI ID', 'data' => 'pdi_id'],
            ['title' => 'IAVM Notice', 'data' => 'iavm'],
            ['title' => 'Title', 'data' => 'title'],
            ['title' => 'Category', 'data' => 'cat'],
            ['title' => 'Link', 'data' => 'link']
        ],
        'draw'            => $draw,
        'recordsTotal'    => $count,
        'recordsFiltered' => $count,
        'data'            => []
    ];

    $db->help->select("sagacity.iavm_notices", null, $where, [
        'order' => 'iavmNoticeNumber'
    ]);
    $rows = $db->help->execute();

    if (is_array($rows) && count($rows) && isset($rows['iavmNoticeNumber'])) {
        $rows = [0 => $rows];
    }

    if (is_array($rows) && count($rows) && isset($rows[0])) {
        foreach ($rows as $row) {
            $cat           = implode("", array_fill(0, $row['stigFindingSeverity'], "I"));
            $ret['data'][] = [
                'pdi_id' => "<a href='#' onclick='javascript:open_pdi(\"{$row['pdi_id']}\");'>{$row['pdi_id']}</a>",
                'iavm'   => $row['iavmNoticeNumber'],
                'title'  => $row['title'],
                'cat'    => $cat,
                'link'   => "<a href='/reference/iavms/{$row['file_name']}' target='_blank'>XML</a>"
            ];
        }
    }
}
else {
    if (strpos($q, "%") === false) {
        $q = "'%{$q}%'";
    }
    $where = [
        [
            'field' => 'pcl.short_title',
            'op'    => LIKE,
            'value' => $q
        ],
        [
            'field'  => 's.description',
            'op'     => LIKE,
            'value'  => $q,
            'sql_op' => 'OR'
        ],
        [
            'field'  => 'pcl.check_contents',
            'op'     => LIKE,
            'value'  => $q,
            'sql_op' => 'OR'
        ]
    ];

    if (!empty($filter['value'])) {
        $where[] = [
            'field'      => 's.stig_id',
            'op'         => LIKE,
            'value'      => "'%{$filter['value']}%'",
            'sql_op'     => 'AND',
            'open-paren' => true
        ];
        $where[] = [
            'field'       => 'gd.vms_id',
            'op'          => LIKE,
            'value'       => "'%{$filter['value']}%'",
            'sql_op'      => 'OR',
            'close-paren' => true
        ];
    }

    $db->help->select_count("sagacity.pdi_catalog pdi", $where, [
        'table_joins' => [
            "LEFT JOIN sagacity.stigs s ON s.pdi_id=pdi.id",
            "LEFT JOIN sagacity.golddisk gd ON gd.pdi_id=pdi.id",
            "LEFT JOIN sagacity.pdi_checklist_lookup pcl ON pdi.id=pcl.pdi_id",
            "LEFT JOIN sagacity.checklist c ON c.id=pcl.checklist_id"
        ]
    ]);
    $count = $db->help->execute();

    $ret = [
        'columns'         => [
            ['title' => 'STIG ID', 'data' => 'stig_id'],
            ['title' => 'VMS ID', 'data' => 'vms_id'],
            ['title' => 'Checklist Name', 'data' => 'name'],
            ['title' => 'Type', 'data' => 'type'],
            ['title' => 'PDI', 'data' => 'pdi_id'],
            ['title' => 'File Name', 'data' => 'file']
        ],
        'draw'            => $draw,
        'recordsTotal'    => $count,
        'recordsFiltered' => $count,
        'data'            => []
    ];

    $db->help->select("sagacity.pdi_catalog pdi", [
        "pdi.id AS 'pdi_id'", "pdi.short_title AS 'Short_Title'",
        "s.stig_id AS 'STIG_ID'", "gd.vms_id AS 'VMS_ID'",
        "c.id AS 'chk_id'", "c.`name` AS 'chk_name'", "c.file_name", "c.`type`", "c.`release`", "c.`ver`"
        ], $where, [
        'table_joins' => [
            "LEFT JOIN sagacity.stigs s ON s.pdi_id=pdi.id",
            "LEFT JOIN sagacity.golddisk gd ON gd.pdi_id=pdi.id",
            "LEFT JOIN sagacity.pdi_checklist_lookup pcl ON pdi.id=pcl.pdi_id",
            "LEFT JOIN sagacity.checklist c ON c.id=pcl.checklist_id"
        ],
        'start'       => $start,
        'limit'       => $len
    ]);

    $rows = $db->help->execute();
    if (is_array($rows) && count($rows) && isset($rows['pdi_id'])) {
        $rows = [0 => $rows];
    }

    if (is_array($rows) && count($rows) && isset($rows[0])) {
        foreach ($rows as $row) {
            $name  = str_replace("Security Technical Implementation Guide", "STIG", $row['chk_name']);
            $title = "{$row['Short_Title']} (<span style = 'font-style:italic;'>from $name</span>)";

            $file_name = basename($row['file_name']);

            $ret['data'][] = [
                'stig_id' => $row['STIG_ID'],
                'vms_id'  => $row['VMS_ID'],
                'name'    => "{$row['chk_name']} V{$row['ver']}R{$row['release']}",
                'type'    => $row['type'],
                'pdi_id'  => "<a href='#' onclick='javascript:open_stig(\"$file_name\", \"{$row['VMS_ID']}\");'>PDI</a>",
                'file'    => "<a href='/reference/stigs/$file_name' target='_blank'><img src='/img/file.png' style='width:25px;' title='$file_name' /></a>"
            ];
        }
    }
}

print header(JSON) . json_encode($ret);