#!/usr/bin/env python
import json
import colorama
import sys
import re
from termcolor import colored
from tabulate import tabulate

'''
Quick script to format the result of a Gitleaks JSON report:
    gitleaks detect --config gitleaks-custom-config.toml --no-banner --report-format json --report-path report.json --source $(pwd) --verbose
    python generate-report-gitleaks.py report.json

Dependencies:
    pip install tabulate colorama termcolor

Gitleaks references:
    https://github.com/gitleaks/gitleaks
    https://gitleaks.io/
'''


def keep_leak(leak_json_entry):
    # Keep a leak by default
    keep = True
    src_file = leak["File"].replace("\\","/")
    content = leak["Secret"]
    # Java property placeholder: ${xxx}
    if len(re.findall(r'\$\{([A-Z0-9._-]+)\}', content, re.IGNORECASE)) > 0:
        keep = False
    # Unix environment variable in shell script: $xxx
    elif (src_file.endswith(".sh") or src_file.endswith(".yml")) and len(re.findall(r'\$([A-Z0-9._-]+)', content, re.IGNORECASE)) > 0:
        keep = False
    # Unix environment variable in CI job descriptor: $xxx
    elif src_file in [".gitlab-ci.yml"] and len(re.findall(r'\$([A-Z0-9._-]+)', content, re.IGNORECASE)) > 0:
        keep = False        
    # Unix environment variable in CI job descriptor: $xxx
    elif src_file.split("/")[-1] in [".gitlab-ci.yml"] and len(re.findall(r'\$([A-Z0-9._-]+)', content, re.IGNORECASE)) > 0:
        keep = False
    # Unix environment variable in Dockerfile descriptor: $xxx
    elif src_file.split("/")[-1] in ["Dockerfile", "Containerfile"] and len(re.findall(r'\$([A-Z0-9._-]+)', content, re.IGNORECASE)) > 0:
        keep = False         
    # Python command line argument: sys.argv[2]
    elif src_file.endswith(".py") and "sys.argv[" in content:
        keep = False
    # JavaScript map file
    elif src_file.endswith(".min.js.map"):
        keep = False
    # CSS file
    elif src_file.endswith(".css"):
        keep = False        
    return keep


report = sys.argv[1]
colorama.init()
with open(report) as f:
    content = f.read()
leaks = json.loads(content)
table_rows = []
table_headers = ["File", "RuleID", "StartLine", "Commit", "Secret"]
git_commit_refs = {}
for leak in leaks:
    if not keep_leak(leak):
        continue
    table_row = []
    for header in table_headers:
        if header == "Tag":
            table_row.append(",".join(leak[header]))
        elif header == "Commit":
            v = leak[header]
            if len(v) == 0:
                v = "NA"
            else:
                v = v[:12]
                git_commit_refs[v] = leak[header]
            table_row.append(v)
        elif header == "Secret":
            v = leak[header][:40]
            v = v.replace("\n", "")
            v = v.replace("\r", "")
            v = v.replace("\t", "")
            table_row.append(v)
        else:
            table_row.append(leak[header])
    table_rows.append(table_row)
table_rows.sort()
print(colored(f"[+] Leaks ({len(table_rows)} founds):", "yellow"))
print(tabulate(table_rows, headers=table_headers))
if len(git_commit_refs) > 0:
    print(" ")
    print(colored(f"[+] Git commit references:", "yellow"))
    table_rows.clear()
    table_headers = ["Commit", "Full identifier"]
    for short_id, full_id in git_commit_refs.items():
        table_rows.append([short_id, full_id])
    table_rows.sort()
    print(tabulate(table_rows, headers=table_headers))