/contrib/matrix_sso_helper.py
https://github.com/poljar/weechat-matrix · Python · 137 lines · 84 code · 34 blank · 19 comment · 13 complexity · 34b4c169869120fea1772e881e11e5a0 MD5 · raw file
- #!/usr/bin/env -S python3 -u
- # Copyright 2019 The Matrix.org Foundation CIC
- #
- # 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 asyncio
- import argparse
- import socket
- import json
- from random import choice
- from aiohttp import web
- # The browsers ban some known ports, the dynamic port range doesn't contain any
- # banned ports, so we use that.
- port_range = range(49152, 65535)
- shutdown_task = None
- def to_weechat(message):
- print(json.dumps(message))
- async def get_token(request):
- global shutdown_task
- async def shutdown():
- await asyncio.sleep(1)
- raise KeyboardInterrupt
- token = request.query.get("loginToken")
- if not token:
- raise KeyboardInterrupt
- message = {
- "type": "token",
- "loginToken": token
- }
- # Send the token to weechat.
- to_weechat(message)
- # Initiate a shutdown.
- shutdown_task = asyncio.ensure_future(shutdown())
- # Respond to the browser.
- return web.Response(text="Continuing in Weechat.")
- def bind_socket(port=None):
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- if port is not None and port != 0:
- sock.bind(("localhost", port))
- return sock
- while True:
- port = choice(port_range)
- try:
- sock.bind(("localhost", port))
- except OSError:
- continue
- return sock
- async def wait_for_shutdown_task(_):
- if not shutdown_task:
- return
- try:
- await shutdown_task
- except KeyboardInterrupt:
- pass
- def main():
- parser = argparse.ArgumentParser(
- description="Start a web server that waits for a SSO token to be "
- "passed with a GET request"
- )
- parser.add_argument(
- "-p", "--port",
- help=("the port that the web server will be listening on, if 0 a "
- "random port should be chosen"
- ),
- type=int,
- default=0
- )
- args = parser.parse_args()
- app = web.Application()
- app.add_routes([web.get('/', get_token)])
- if not 0 <= args.port <= 65535:
- raise ValueError("Port needs to be 0-65535")
- try:
- sock = bind_socket(args.port)
- except OSError as e:
- message = {
- "type": "error",
- "message": str(e),
- "code": e.errno
- }
- to_weechat(message)
- return
- host, port = sock.getsockname()
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- message = {
- "type": "redirectUrl",
- "host": host,
- "port": port
- }
- to_weechat(message)
- app.on_shutdown.append(wait_for_shutdown_task)
- web.run_app(app, sock=sock, handle_signals=True, print=None)
- if __name__ == "__main__":
- main()