# Copyright (C) 2026 saces@c-base.org # SPDX-License-Identifier: AGPL-3.0-only import getpass from datetime import datetime import click from pygomx import CliV0 @click.command() @click.option("-u", "--url", "hs_url", metavar="url", help="homeserver url") @click.option("-t", "--token", "token", metavar="token", help="access token") @click.option( "--json", "show_json", is_flag=True, help="show json as returned from server." ) @click.argument("devices", metavar="DeviceID", nargs=-1) @click.option( "-l", "--logout", "logout_type", type=click.Choice(["all", "other", "self"]), help="logout devices", ) def logout(hs_url, token, devices, logout_type, show_json): """List or logout devices. \b mxlogout [--json] list all devices mxlogout --all logout all devices mxlogout --self logout this device mxlogout --other logout all other devices (requires auth) mxlogout deviceid [deviceid]... logout given devices (requires auth) """ if len(devices) > 0 and logout_type is not None: raise ValueError("you can't get both.") if hs_url is None and token is None: cli = CliV0.from_mxpass(".mxpass", "*", "*", "*") else: cli = CliV0(hs_url, token) match logout_type: case "self": do_logout(cli, all=False) return case "all": do_logout(cli, all=True) return if len(devices) > 0: device_list = list(devices) whoami_dict = cli.Whoami() self_user_id = whoami_dict["user_id"] do_logout_devices(cli, device_list, self_user_id) return reqData = {"method": "GET", "path": ["_matrix", "client", "v3", "devices"]} raw_device_dict = cli.Generic(reqData) if logout_type == "other": whoami_dict = cli.Whoami() self_device_id = whoami_dict["device_id"] self_user_id = whoami_dict["user_id"] device_list = [] for device in raw_device_dict["devices"]: if device["device_id"] != self_device_id: device_list += [ device["device_id"], ] if len(device_list) > 0: do_logout_devices(cli, device_list, self_user_id) return if show_json: print(raw_device_dict) return max_len = 0 for device in raw_device_dict["devices"]: max_len = max(max_len, len(device["device_id"])) for device in raw_device_dict["devices"]: date_object = datetime.fromtimestamp(device["last_seen_ts"] / 1000) print( device["device_id"], " " * (max_len - len(device["device_id"])), date_object, device["last_seen_ip"], device["display_name"], ) date_object = datetime.fromtimestamp(device["last_seen_ts"] / 1000) def do_logout(cli, all): reqData = { "method": "POST", "path": ["_matrix", "client", "v3", "logout"], } if all: reqData["path"] += ["all"] res = cli.Generic(reqData) print(res) def do_logout_devices(cli, devices, user_id): reqData = { "method": "POST", "path": ["_matrix", "client", "v3", "delete_devices"], "payload": { "devices": devices, "auth": { "type": "m.login.password", "password": getpass.getpass(prompt="Password: "), "identifier": { "type": "m.id.user", "user": user_id, }, }, }, } res = cli.Generic(reqData) print(res)