130 lines
3.6 KiB
Python
130 lines
3.6 KiB
Python
|
|
# 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)
|