1import argparse
2import json
3import logging
4import sys
5
6import dns.resolver
7import urllib2
8from signedjson.key import decode_verify_key_bytes, write_signing_keys
9from signedjson.sign import verify_signed_json
10from unpaddedbase64 import decode_base64
11
12
13def get_targets(server_name):
14    if ":" in server_name:
15        target, port = server_name.split(":")
16        yield (target, int(port))
17        return
18    try:
19        answers = dns.resolver.query("_matrix._tcp." + server_name, "SRV")
20        for srv in answers:
21            yield (srv.target, srv.port)
22    except dns.resolver.NXDOMAIN:
23        yield (server_name, 8448)
24
25
26def get_server_keys(server_name, target, port):
27    url = "https://%s:%i/_matrix/key/v1" % (target, port)
28    keys = json.load(urllib2.urlopen(url))
29    verify_keys = {}
30    for key_id, key_base64 in keys["verify_keys"].items():
31        verify_key = decode_verify_key_bytes(key_id, decode_base64(key_base64))
32        verify_signed_json(keys, server_name, verify_key)
33        verify_keys[key_id] = verify_key
34    return verify_keys
35
36
37def main():
38
39    parser = argparse.ArgumentParser()
40    parser.add_argument("signature_name")
41    parser.add_argument(
42        "input_json", nargs="?", type=argparse.FileType("r"), default=sys.stdin
43    )
44
45    args = parser.parse_args()
46    logging.basicConfig()
47
48    server_name = args.signature_name
49    keys = {}
50    for target, port in get_targets(server_name):
51        try:
52            keys = get_server_keys(server_name, target, port)
53            print("Using keys from https://%s:%s/_matrix/key/v1" % (target, port))
54            write_signing_keys(sys.stdout, keys.values())
55            break
56        except Exception:
57            logging.exception("Error talking to %s:%s", target, port)
58
59    json_to_check = json.load(args.input_json)
60    print("Checking JSON:")
61    for key_id in json_to_check["signatures"][args.signature_name]:
62        try:
63            key = keys[key_id]
64            verify_signed_json(json_to_check, args.signature_name, key)
65            print("PASS %s" % (key_id,))
66        except Exception:
67            logging.exception("Check for key %s failed" % (key_id,))
68            print("FAIL %s" % (key_id,))
69
70
71if __name__ == "__main__":
72    main()
73