diff --git a/tools/make-tls-ct-logids.py b/tools/make-tls-ct-logids.py index 8af617c993..cc8ae5a0e8 100755 --- a/tools/make-tls-ct-logids.py +++ b/tools/make-tls-ct-logids.py @@ -9,7 +9,9 @@ import argparse from base64 import b64decode, b64encode +from enum import Enum import itertools +import os import requests from hashlib import sha256 @@ -19,12 +21,18 @@ HEADER = "/* Generated by tools/make-tls-ct-logids.py\n" # See also https://www.certificate-transparency.org/known-logs CT_JSON_URL = 'https://www.gstatic.com/ct/log_list/v3/all_logs_list.json' # File to be patched -SOURCE_FILE = "epan/dissectors/packet-tls-utils.c" +SOURCE_FILE = os.path.join('epan', 'dissectors', 'packet-tls-utils.c') # Maximum elements per line in the value array. 11 is chosen because it results # in output consistent with clang-format. BYTES_PER_LINE = 11 +class SourceStage(Enum): + BEGIN = 1 + IN_METAINFO = 2 + IN_BLOCK = 3 + END = 4 + def escape_c(s): return s.replace('\\', '\\\\').replace('"', '\\"') @@ -36,47 +44,55 @@ def byteshex(b): def process_json(obj, lastmod): logs = list(itertools.chain(*[op['logs'] for op in obj['operators']])) - lines = HEADER - lines += " * Last-Modified %s, %s entries. */\n" % (lastmod, len(logs)) - lines += "static const bytes_string ct_logids[] = {\n" + metainfo, block = HEADER, '' + metainfo += " * Last-Modified %s, %s entries. */\n" % (lastmod, len(logs)) + block += "static const bytes_string ct_logids[] = {\n" for entry in logs: desc = entry["description"] pubkey_der = b64decode(entry["key"]) key_id = sha256(pubkey_der).digest() - lines += ' { (const guint8[]){\n' + block += ' { (const guint8[]){\n' for offset in range(0, len(key_id), BYTES_PER_LINE): - lines += ' %s\n' % \ + block += ' %s\n' % \ byteshex(key_id[offset:offset+BYTES_PER_LINE]) - lines += ' },\n' - lines += ' %d, "%s" },\n' % (len(key_id), escape_c(desc)) - lines += " { NULL, 0, NULL }\n" - lines += "};\n" - return lines + block += ' },\n' + block += ' %d, "%s" },\n' % (len(key_id), escape_c(desc)) + block += " { NULL, 0, NULL }\n" + block += "};\n" + return metainfo, block -def parse_source(): +def parse_source(source_path): """ Reads the source file and tries to split it in the parts before, inside and after the block. """ - begin, block, end = '', '', '' - # Stages: 1 (before block), 2 (in block, skip), 3 (after block) - stage = 1 - with open(SOURCE_FILE) as f: + begin, metainfo, block, end = '', '', '', '' + # Stages: BEGIN (before block), IN_METAINFO, IN_BLOCK (skip), END + stage = SourceStage.BEGIN + with open(source_path) as f: for line in f: - if line == HEADER: - stage = 2 # Begin of block - if stage == 1: + if line.startswith('/* Generated by '): + stage = SourceStage.IN_METAINFO + + + if stage == SourceStage.BEGIN: begin += line - elif stage == 2: + elif stage == SourceStage.IN_METAINFO: + metainfo += line + elif stage == SourceStage.IN_BLOCK: block += line if line.startswith('}'): - stage = 3 # End of block reached - elif stage == 3: + stage = SourceStage.END + elif stage == SourceStage.END: end += line - if stage != 3: - raise RuntimeError("Could not parse file (in stage %d)" % stage) - return begin, block, end + + if line.startswith(' * Last-Modified '): + stage = SourceStage.IN_BLOCK + + if stage != SourceStage.END: + raise RuntimeError("Could not parse file (in stage %s)" % stage.name) + return begin, metainfo, block, end parser = argparse.ArgumentParser() @@ -86,21 +102,24 @@ parser.add_argument("--update", action="store_true", def main(): args = parser.parse_args() + this_dir = os.path.dirname(__file__) r = requests.get(CT_JSON_URL) - code = process_json(r.json(), lastmod=r.headers['Last-Modified']) + j_metainfo, j_block = process_json(r.json(), lastmod=r.headers['Last-Modified']) + source_path = os.path.join(this_dir, '..', SOURCE_FILE) if args.update: - begin, block, end = parse_source() - if block == code: + s_begin, _, s_block, s_end = parse_source(source_path) + if s_block == j_block: print("File is up-to-date") else: - with open(SOURCE_FILE, "w") as f: - f.write(begin) - f.write(code) - f.write(end) - print("Updated %s" % SOURCE_FILE) + with open(source_path, "w") as f: + f.write(s_begin) + f.write(j_metainfo) + f.write(j_block) + f.write(s_end) + print("Updated %s" % source_path) else: - print(code) + print(j_metainfo, j_block) if __name__ == '__main__':