add tool for logging out (other devices)

This commit is contained in:
saces 2026-03-16 10:48:11 +01:00
parent 1bfae104fc
commit c890c49c7b
4 changed files with 132 additions and 0 deletions

View file

@ -60,6 +60,7 @@ usage:
mxdiscover --help
mxpassitem --help
mxwhoami --help
mxlogout --help
mxtoken
mxaccountinfo
mxclearaccount

View file

@ -36,6 +36,7 @@ mxdiscover = "pymxutils.mxutils:discoverhs"
mxwhoami = "pymxutils.mxutils:whoami"
mxtoken = "pymxutils.mxutils:mktoken"
mxaccountinfo = "pymxutils.mxutils:accountinfo"
mxlogout = "pymxutils.mxutils:logout"
mxclearaccount = "pymxutils.mxutils:clearaccount"
mxserverinfo = "pymxutils.mxutils:serverinfo"
mxpassitem = "pymxutils.mxutils:passitem"

View file

@ -5,3 +5,4 @@ from .accountinfo import accountinfo as accountinfo
from .clearaccount import clearaccount as clearaccount
from .serverinfo import serverinfo as serverinfo
from .passitem import passitem as passitem
from .logout import logout as logout

View file

@ -0,0 +1,129 @@
# 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)