#!/usr/bin/env python3
"""Generate and HTML output with all current CVEs for a given manifest.

Usage:
  python3 generate-cve-report.py path/to/manifest.json output.html

This requires you to run update-local-cve-database.py first in the
same current directory.
"""

import json
import sys
import sqlite3

conn = sqlite3.connect('data-2.db')
c = conn.cursor()

with open(sys.argv[1], 'rb') as f:
    manifest = json.load(f)

with open(sys.argv[2], 'w') as out:
    out.write('<!DOCTYPE html>\n')
    out.write('<html><head><title>Report</title></head><body><table>\n')

    entries = []
    for module in manifest["modules"]:
        name = module["name"]
        sources = module["sources"]
        cpe = module["x-cpe"]
        product = cpe["product"]
        version = cpe.get("version")
        vendor = cpe.get("vendor")
        patches = cpe.get("patches", [])
        ignored = cpe.get("ignored", [])
        if not version:
            print("{} is missing a version".format(name))
            continue

        if vendor:
            c.execute("""SELECT cve.id, cve.summary, cve.score FROM cve, product_vuln
                             WHERE cve.id=product_vuln.cve_id
                               AND product_vuln.name=?
                               AND product_vuln.version=?
                               AND product_vuln.vendor=?""",
                      (product, version, vendor))
        else:
            c.execute("""SELECT cve.id, cve.summary, cve.score FROM cve, product_vuln
                             WHERE cve.id=product_vuln.cve_id
                               AND product_vuln.name=?
                               AND product_vuln.version=?""",
                      (product, version))
        while True:
            row = c.fetchone()
            if row is None:
                break
            if row[0] in patches or row[0] in ignored:
                continue
            entries.append((row[0], name, version, row[1], row[2]))

    def by_score(entry, ):
        ID, name, version, summary, score = entry
        try:
            return float(score)
        except ValueError:
            return float("inf")

    for ID, name, version, summary, score in sorted(entries, key=by_score, reverse=True):
        out.write('<tr>')
        out.write('<td><a href="https://nvd.nist.gov/vuln/detail/{ID}">{ID}</a></td>'.format(ID=ID))
        for d in [name, version, summary, score]:
            out.write('<td>{}</td>'.format(d))
        out.write('</tr>\n')

    out.write('</table></html>\n')
