<?php
/***
 * $>php CSharpConfChecker.php /path/to/src/
 * will output csv with status of packages (out of dat, known vulnerable)
 */

$total = 0;

function findConfFiles($folderPath) {
    $confFiles = array();
    $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folderPath));
    foreach($iterator as $file) {
        //echo "$file          \r";
        if ($file->isFile() && $file->getExtension() == 'config') {
            $confFiles[] = $file->getPathname();
        }
    }
    return $confFiles;
}

function parseConfFiles($confFiles) {
    global $total;
    $result = array();
    foreach($confFiles as $file) {
        $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        foreach($lines as $line) {
            if(strpos($line, 'id=') !== false && strpos($line, 'version=') !== false) {
                $id = '';
                $version = '';
                preg_match('/id=(\S+)/', $line, $idMatch);
                if(!empty($idMatch)) {
                    $id = $idMatch[1];
                }
                preg_match('/version=(\S+)/', $line, $versionMatch);
                if(!empty($versionMatch)) {
                    $version = $versionMatch[1];
                }
                if(!empty($id) && !empty($version)) {
                    if(empty($result[$id][$version])){
                        $total++;
                    }
                    $result[$id][$version][] = $file;
                }
            }
        }
    }

     // sort by id and then by version number
    uksort($result, function($a, $b) use ($result) {
        $aVersions = array_keys($result[$a]);
        $bVersions = array_keys($result[$b]);
        $aVersion = $aVersions[count($aVersions) - 1];
        $bVersion = $bVersions[count($bVersions) - 1];
        $aVersion = preg_replace('/[^0-9.]/', '', $aVersion);
        $bVersion = preg_replace('/[^0-9.]/', '', $bVersion);
        if($a == $b) {
            return version_compare($aVersion, $bVersion);
        } else {
            return strcmp($a, $b);
        }
    });
    return $result;
}

function downloadUrls($parsedConf) {
    global $total;
    $count = 0;
    foreach ($parsedConf as $id => $versions) {
        foreach ($versions as $version => $files) {
            $url = "https://www.nuget.org/packages/" . str_replace('"', '', trim($id)) . "/" . str_replace('"', '', trim($version));
            $count++;
            echo "downloading: $count of $total    \r";
            $response = getdataz($url);

            if (strpos($response, 'This package has at least one') !== false) {
                $parsedConf[$id][$version]['status'] = 'vulnerable';
            } elseif (strpos($response, 'There is a newer version of this package') !== false) {
                $parsedConf[$id][$version]['status'] = 'outdated';
            }

        }
    }
    echo "downloaded all\n";
    return $parsedConf;
}

function getdataz($target){
    $ch = curl_init($target);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);

    return $result;
}

$folderPath = isset($argv[1]) ? $argv[1] : '';
if (!empty($folderPath)) {
    echo "searching $folderPath\n";
    $confFiles = findConfFiles($folderPath);
    echo "parsing\n";
    $parsedConfFiles = parseConfFiles($confFiles);
    echo "found: $total\n";
    $parsedConfFiles = downloadUrls($parsedConfFiles);
    
    $csvString = "id, version, status, file\n";
    foreach ($parsedConfFiles as $id => $versions) {

        foreach ($versions as $version => $files) {
            $status = isset($files['status']) ? $files['status'] : '';
            $file = isset($files[0]) ? $files[0] : '';
              
            // Add a row to the CSV
            $csvString .= "$id, $version, $status, $file\n";
        }       
    }
    echo $csvString;
}
?>
