#!/usr/bin/env python # # Copyright 2020 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import json import sys from json import JSONDecodeError import yaml from signedjson.key import read_signing_keys from signedjson.sign import sign_json from synapse.util import json_encoder def main(): parser = argparse.ArgumentParser( description="""Adds a signature to a JSON object. Example usage: $ scripts-dev/sign_json.py -N test -k localhost.signing.key "{}" {"signatures":{"test":{"ed25519:a_ZnZh":"LmPnml6iM0iR..."}}} """, formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument( "-N", "--server-name", help="Name to give as the local homeserver. If unspecified, will be " "read from the config file.", ) parser.add_argument( "-k", "--signing-key-path", help="Path to the file containing the private ed25519 key to sign the " "request with.", ) parser.add_argument( "-c", "--config", default="homeserver.yaml", help=( "Path to synapse config file, from which the server name and/or signing " "key path will be read. Ignored if --server-name and --signing-key-path " "are both given." ), ) input_args = parser.add_mutually_exclusive_group() input_args.add_argument("input_data", nargs="?", help="Raw JSON to be signed.") input_args.add_argument( "-i", "--input", type=argparse.FileType("r"), default=sys.stdin, help=( "A file from which to read the JSON to be signed. If neither --input nor " "input_data are given, JSON will be read from stdin." ), ) parser.add_argument( "-o", "--output", type=argparse.FileType("w"), default=sys.stdout, help="Where to write the signed JSON. Defaults to stdout.", ) args = parser.parse_args() if not args.server_name or not args.signing_key_path: read_args_from_config(args) with open(args.signing_key_path) as f: key = read_signing_keys(f)[0] json_to_sign = args.input_data if json_to_sign is None: json_to_sign = args.input.read() try: obj = json.loads(json_to_sign) except JSONDecodeError as e: print("Unable to parse input as JSON: %s" % e, file=sys.stderr) sys.exit(1) if not isinstance(obj, dict): print("Input json was not an object", file=sys.stderr) sys.exit(1) sign_json(obj, args.server_name, key) for c in json_encoder.iterencode(obj): args.output.write(c) args.output.write("\n") def read_args_from_config(args: argparse.Namespace) -> None: with open(args.config, "r") as fh: config = yaml.safe_load(fh) if not args.server_name: args.server_name = config["server_name"] if not args.signing_key_path: args.signing_key_path = config["signing_key_path"] if __name__ == "__main__": main()