From 5473ba1ad8559f82bcb40578bf0ba7ad627a0500 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 17 Nov 2020 13:46:22 +0000 Subject: [PATCH 1/5] Add a script to sign arbitrary json objects. --- changelog.d/8772.misc | 1 + mypy.ini | 1 + scripts-dev/sign_json.py | 127 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 changelog.d/8772.misc create mode 100755 scripts-dev/sign_json.py diff --git a/changelog.d/8772.misc b/changelog.d/8772.misc new file mode 100644 index 000000000000..d74d0a3d5d87 --- /dev/null +++ b/changelog.d/8772.misc @@ -0,0 +1 @@ +Add a commandline script to sign arbitrary json objects. diff --git a/mypy.ini b/mypy.ini index fc9f8d805069..53c96712a1ce 100644 --- a/mypy.ini +++ b/mypy.ini @@ -8,6 +8,7 @@ show_traceback = True mypy_path = stubs warn_unreachable = True files = + scripts-dev/sign_json.py, synapse/api, synapse/appservice, synapse/config, diff --git a/scripts-dev/sign_json.py b/scripts-dev/sign_json.py new file mode 100755 index 000000000000..ffc91631cf4f --- /dev/null +++ b/scripts-dev/sign_json.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# +# -*- coding: utf-8 -*- +# 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 a dict", 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() From 16cc59878d1dd8a2241fc197b0e75db6d9fedf6a Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 17 Nov 2020 14:16:42 +0000 Subject: [PATCH 2/5] fix lint --- scripts-dev/sign_json.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-dev/sign_json.py b/scripts-dev/sign_json.py index ffc91631cf4f..127cc195ca87 100755 --- a/scripts-dev/sign_json.py +++ b/scripts-dev/sign_json.py @@ -30,7 +30,7 @@ def main(): parser = argparse.ArgumentParser( description="""Adds a signature to a JSON object. -Example usage: +Example usage: $ scripts-dev/sign_json.py -N test -k localhost.signing.key "{}" {"signatures":{"test":{"ed25519:a_ZnZh":"LmPnml6iM0iR..."}}} From ce6ca576ba14536340628f20a023bacee2d23183 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Thu, 19 Nov 2020 18:34:54 +0000 Subject: [PATCH 3/5] Update scripts-dev/sign_json.py Co-authored-by: Patrick Cloke --- scripts-dev/sign_json.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-dev/sign_json.py b/scripts-dev/sign_json.py index 127cc195ca87..44553fb79aa8 100755 --- a/scripts-dev/sign_json.py +++ b/scripts-dev/sign_json.py @@ -105,7 +105,7 @@ def main(): sys.exit(1) if not isinstance(obj, dict): - print("Input json was not a dict", file=sys.stderr) + print("Input json was not an object", file=sys.stderr) sys.exit(1) sign_json(obj, args.server_name, key) From f2a1e8850f9f56558bbe968daf963f11e6ee8c09 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 20 Nov 2020 14:26:52 +0000 Subject: [PATCH 4/5] Drop `.py` suffix it's annoying noise. --- scripts-dev/{sign_json.py => sign_json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts-dev/{sign_json.py => sign_json} (100%) diff --git a/scripts-dev/sign_json.py b/scripts-dev/sign_json similarity index 100% rename from scripts-dev/sign_json.py rename to scripts-dev/sign_json From 2488b8714f93efbec5e8c220a1709ff072166f93 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 24 Nov 2020 11:36:53 +0000 Subject: [PATCH 5/5] fix mypy --- mypy.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy.ini b/mypy.ini index 53c96712a1ce..b3261b2a7ebb 100644 --- a/mypy.ini +++ b/mypy.ini @@ -8,7 +8,7 @@ show_traceback = True mypy_path = stubs warn_unreachable = True files = - scripts-dev/sign_json.py, + scripts-dev/sign_json, synapse/api, synapse/appservice, synapse/config,