aboutsummaryrefslogtreecommitdiffstats
path: root/graph-to-full.py
blob: eedc3bffe764b54bb6eb1f366f37b90f2858f0f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright © 2018-2024 by The Linux Foundation and contributors
__author__ = 'Konstantin Ryabitsev <konstantin@linuxfoundation.org>'

import sys
import sqlite3

import wotmate
import pydotplus.graphviz as pd


def get_key_paths(c, b_p_rowid, maxdepth=5):
    # Next, get rowids of all keys with full trust
    f_p_rowids = wotmate.get_all_full_trust(c)

    if not f_p_rowids:
        logger.critical('No fully trusted keys found in the db')
        sys.exit(1)

    paths = []
    ignorekeys = [item for sublist in f_p_rowids for item in sublist]
    lookedat = 0

    logger.info('Found %s fully trusted keys in the db' % len(f_p_rowids))
    for (f_p_rowid,) in f_p_rowids:
        lookedat += 1
        logger.info('Trying "%s" (%s/%s)' %
                    (wotmate.get_uiddata_by_pubrow(c, f_p_rowid), lookedat, len(f_p_rowids)))

        path = wotmate.get_shortest_path(c, f_p_rowid, b_p_rowid, 0, maxdepth-1, ignorekeys)

        if path:
            logger.info('`- found a path with %s members' % len(path))
            paths.append(path)
            # we want to find maximum paths, so we unset _seenkeys
            wotmate._seenkeys = []
            if len(path) > 2:
                ignorekeys += path[1:-1]

    if not paths:
        logger.critical('No paths found to any fully trusted keys')
        sys.exit(1)

    culled = wotmate.cull_redundant_paths(paths)
    logger.info('%s paths left after culling' % len(culled))

    return culled


if __name__ == '__main__':
    import argparse
    ap = argparse.ArgumentParser(
        description='Make a graph from any key to fully trusted keys',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )

    ap.add_argument('--quiet', action='store_true',
                    default=False,
                    help='Be quiet and only output errors')
    ap.add_argument('--maxdepth', default=4, type=int,
                    help='Try up to this maximum depth')
    ap.add_argument('--font', default='droid sans,dejavu sans,helvetica',
                    help='Font to use in the graph')
    ap.add_argument('--fontsize', default='11',
                    help='Font size to use in the graph')
    ap.add_argument('--dbfile', default='siginfo.db',
                    help='Sig database to use')
    ap.add_argument('--out', default='graph.png',
                    help='Write graph into this file, guessing the output format by extension')
    ap.add_argument('--show-trust', action='store_true', dest='show_trust',
                    default=False,
                    help='Display validity and trust values')
    ap.add_argument('key_id', nargs=1, default=False,
                    help='Bottom key ID for path tracing')

    cmdargs = ap.parse_args()

    logger = wotmate.get_logger(cmdargs.quiet)

    dbconn = sqlite3.connect(cmdargs.dbfile)
    cursor = dbconn.cursor()

    if len(cmdargs.key_id) != 1:
        logger.critical('Please provide a single key id for path tracing')
        sys.exit(1)

    to_rowid = wotmate.get_pubrow_id(cursor, cmdargs.key_id[0])
    if to_rowid is None:
        sys.exit(1)

    key_paths = get_key_paths(cursor, to_rowid, cmdargs.maxdepth)

    graph = pd.Dot(
        graph_type='digraph',
    )
    graph.set_node_defaults(
        fontname=cmdargs.font,
        fontsize=cmdargs.fontsize,
    )

    wotmate.draw_key_paths(cursor, key_paths, graph, cmdargs.show_trust)

    chunks = cmdargs.out.split('.')
    outformat = chunks[-1]
    graph.write(cmdargs.out, format=outformat)
    logger.info('Wrote %s' % cmdargs.out)