diff --git a/scripts/export_signing_key b/scripts/export_signing_key
new file mode 100755
index 0000000000..8aec9d802b
--- /dev/null
+++ b/scripts/export_signing_key
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright 2019 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 sys
+import time
+from typing import Optional
+
+import nacl.signing
+from signedjson.key import encode_verify_key_base64, get_verify_key, read_signing_keys
+
+
+def exit(status: int = 0, message: Optional[str] = None):
+ if message:
+ print(message, file=sys.stderr)
+ sys.exit(status)
+
+
+def format_plain(public_key: nacl.signing.VerifyKey):
+ print(
+ "%s:%s %s"
+ % (public_key.alg, public_key.version, encode_verify_key_base64(public_key),)
+ )
+
+
+def format_for_config(public_key: nacl.signing.VerifyKey, expiry_ts: int):
+ print(
+ ' "%s:%s": { key: "%s", expired_ts: %i }'
+ % (
+ public_key.alg,
+ public_key.version,
+ encode_verify_key_base64(public_key),
+ expiry_ts,
+ )
+ )
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument(
+ "key_file", nargs="+", type=argparse.FileType("r"), help="The key file to read",
+ )
+
+ parser.add_argument(
+ "-x",
+ action="store_true",
+ dest="for_config",
+ help="format the output for inclusion in the old_signing_keys config setting",
+ )
+
+ parser.add_argument(
+ "--expiry-ts",
+ type=int,
+ default=int(time.time() * 1000) + 6*3600000,
+ help=(
+ "The expiry time to use for -x, in milliseconds since 1970. The default "
+ "is (now+6h)."
+ ),
+ )
+
+ args = parser.parse_args()
+
+ formatter = (
+ (lambda k: format_for_config(k, args.expiry_ts))
+ if args.for_config
+ else format_plain
+ )
+
+ keys = []
+ for file in args.key_file:
+ try:
+ res = read_signing_keys(file)
+ except Exception as e:
+ exit(
+ status=1,
+ message="Error reading key from file %s: %s %s"
+ % (file.name, type(e), e),
+ )
+ res = []
+ for key in res:
+ formatter(get_verify_key(key))
|