Skip to content

Commit

Permalink
Merge branch 'release/v0.11.1'
Browse files Browse the repository at this point in the history
* release/v0.11.1:
  Bump version from 0.11.0 to 0.11.1
  ssh: create known_hosts entry, if it does not exist (#232)
  Fix broken addons: purge-history, adduser, deluser, delroom, server-notice (#234)
  • Loading branch information
MichaelSasser committed Sep 25, 2021
2 parents 3bee62a + 207efba commit d6a15a9
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 104 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@ This is the changelog of MatrixCtl. You can find the issue tracker on

.. towncrier release notes start
0.11.1 (2021-09-25)
===================

Features & Improvements
-----------------------

- ``paramiko`` now creates a ``known_hosts`` entry, if it does not exist.
(`#231 <https://github.com/MichaelSasser/matrixctl/issues/231>`_)


Bugfixes
--------

- Fix: ``adduser``, ``deluser``, ``delroom``, ``server-notice``,
``purge-history``. (`#233
<https://github.com/MichaelSasser/matrixctl/issues/233>`_)


0.11.0 (2021-09-21)
===================

Expand Down
2 changes: 1 addition & 1 deletion matrixctl/addons/adduser/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def addon(arg: Namespace, yaml: YAML) -> int:
domain=yaml.get("server", "api", "domain"),
token=yaml.get("server", "api", "token"),
path=f"users/@{arg.user}:{yaml.get('server', 'api','domain')}",
data={"password": passwd, "admin": arg.admin},
json={"password": passwd, "admin": arg.admin},
method="PUT",
)
try:
Expand Down
2 changes: 1 addition & 1 deletion matrixctl/addons/delroom/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def addon(arg: Namespace, yaml: YAML) -> int:
path="purge_room",
method="POST",
api_version="v1",
data={"room_id": arg.RoomID},
json={"room_id": arg.RoomID},
)

try:
Expand Down
2 changes: 1 addition & 1 deletion matrixctl/addons/deluser/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def addon(arg: Namespace, yaml: YAML) -> int:
path=f"deactivate/@{arg.user}:{yaml.get('server', 'api','domain')}",
api_version="v1",
method="POST",
data={"erase": True},
json={"erase": True},
)
try:
request(req)
Expand Down
32 changes: 6 additions & 26 deletions matrixctl/addons/purge_history/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,19 @@ def addon(arg: Namespace, yaml: YAML) -> int:
Non-zero value indicates error code, or zero on success.
"""
arg.room_id = arg.room_id.strip()

request_body: dict[str, str | int] = dialog_input(arg)

logger.debug(f"{request_body = }")

req: RequestBuilder = RequestBuilder(
token=yaml.get("server", "api", "token"),
domain=yaml.get("server", "api", "domain"),
path=f"purge_history/{arg.room_id}",
path=f"purge_history/{arg.room_id.strip()}",
method="POST",
api_version="v1",
data=request_body,
json=request_body,
)

try:
Expand All @@ -86,30 +90,6 @@ def addon(arg: Namespace, yaml: YAML) -> int:

logger.debug(f"{response=}")
return handle_purge_status(yaml, response["purge_id"])
###################
# while True:
# status_response: JsonDict | None = get_purge_status(
# yaml, response["purge_id"]
# )
#
# if status_response is not None:
# debug(f"{status_response=}")
# if status_response["status"] == "complete":
# print("Done...")
# return 0
# if status_response["status"] == "failed":
# fatal("The server returned, that the purge aproach failed.")
# break
# if status_response["status"] == "active":
# info(
# "The server is still purging historic message content. "
# "Please wait..."
# )
# sleep(2) # wait 2 seconds before try again
# continue
# break
#
# return 1


# vim: set ft=python :
6 changes: 4 additions & 2 deletions matrixctl/addons/purge_history/dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import logging
import sys
import time

from argparse import Namespace
from typing import NoReturn
Expand Down Expand Up @@ -67,8 +68,8 @@ def dialog_input(arg: Namespace) -> dict[str, str | int] | NoReturn:
if arg.local_events:
print(
"You are about to delete *local* message events from the "
"Database. As they may represent the only copies of this content "
"in existence, you need to conform this action."
"Database. As they may represent the only copy of this content "
"in existence, you need to confirm this action."
)
if not ask_question("Do you want to continue?"):
sys.exit(0)
Expand All @@ -79,6 +80,7 @@ def dialog_input(arg: Namespace) -> dict[str, str | int] | NoReturn:
print("You are about to delete all mesage events except the last one.")
if not ask_question("Do you want to continue?"):
sys.exit(0)
request_body["purge_up_to_ts"] = int(round(time.time() * 1000))
else:
point_in_time: dict[str, str | int] | None = check_point_in_time(
arg.event_or_timestamp
Expand Down
3 changes: 2 additions & 1 deletion matrixctl/addons/purge_history/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ def handle_purge_status(yaml: YAML, purge_id: str) -> int:
path=f"purge_history_status/{purge_id}",
method="GET",
api_version="v1",
timeout=10.0, # 5 (default) -> 10
)

while True:

sleep(5)
try:
response: JsonDict = request(req).json()
except InternalResponseError:
Expand All @@ -92,7 +94,6 @@ def handle_purge_status(yaml: YAML, purge_id: str) -> int:
"The server is still purging historic message content. "
"Please wait..."
)
sleep(2) # wait 2 seconds before try again
continue
break
return 0
Expand Down
2 changes: 1 addition & 1 deletion matrixctl/addons/server_notice/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def addon(arg: Namespace, yaml: YAML) -> int:
path="send_server_notice",
method="POST",
api_version="v1",
data={
json={
"user_id": (
f"@{arg.username}:" f"{yaml.get('server', 'api', 'domain')}"
),
Expand Down
1 change: 0 additions & 1 deletion matrixctl/addons/upload/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def addon(arg: Namespace, yaml: YAML) -> int:
api_path="_matrix/media",
method="POST",
api_version="r0",
json=False,
headers={"Content-Type": file_type},
content=file,
)
Expand Down
51 changes: 33 additions & 18 deletions matrixctl/handlers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import asyncio
import logging
import math
import sys
import typing
import urllib.parse

Expand Down Expand Up @@ -59,13 +60,14 @@ class RequestBuilder:
subdomain: str = "matrix"
api_path: str = "_synapse/admin"
api_version: str = "v2"
data: dict[str, typing.Any] | None = None
content: bytes | None = None
data: dict[str, typing.Any] | None = None # just key/value store
json: dict[str, typing.Any] | None = None # json
content: bytes | None = None # bytes
method: str = "GET"
json: bool = True
params: dict[str, str | int] = {}
headers: dict[str, str] = {}
concurrent_limit: int = 4
timeout: float = 5.0 # seconds
success_codes: tuple[int, ...] = (
200,
201,
Expand Down Expand Up @@ -139,11 +141,13 @@ def __repr__(self) -> str:
f"headers={self.headers}, params={self.params}, data="
f"{'[binary]' if isinstance(self.data, bytes) else self.data} "
f"success_codes={self.success_codes}, json={self.json}, "
f"token=[redacted (length={len(self.token)})])}}"
f"token=[redacted (length={len(self.token)})], "
f"timeout={self.timeout}, "
f"concurrent_limit={self.concurrent_limit})}}"
)


def _request(req: RequestBuilder) -> httpx.Response:
def _request(request_config: RequestBuilder) -> httpx.Response:
"""Send an syncronus request to the synapse API and receive a response.
Attributes
Expand All @@ -158,18 +162,20 @@ def _request(req: RequestBuilder) -> httpx.Response:
"""

logger.debug("repr: %s", repr(req))
logger.debug("repr: %s", repr(request_config))

with httpx.Client(
http2=True,
) as client:
response: httpx.Response = client.request(
method=req.method,
data=req.data,
content=req.content,
url=str(req),
params=req.params,
headers=req.headers_with_auth,
method=request_config.method,
data=request_config.data,
json=request_config.json,
content=request_config.content,
url=str(request_config),
params=request_config.params,
headers=request_config.headers_with_auth,
timeout=request_config.timeout,
allow_redirects=False,
)

Expand All @@ -183,20 +189,24 @@ def _request(req: RequestBuilder) -> httpx.Response:
"matrix_nginx_proxy_proxy_matrix_client_redirect_root_uri_to"
'_domain: ""'
)
raise ExitQWorker() # TODO

sys.exit(1)
if response.status_code == 404:
logger.critical(
"You need to make sure, that your vars.yml contains the "
"The server returned an 404 error. This can have two causes. "
"The first one is, you try to request a ressource, which does not "
"exist. The second one is, your API endpoint is disabled."
"Make sure, that your vars.yml contains the "
"following excessive long line:\n\n"
"matrix_nginx_proxy_proxy_matrix_client_api_forwarded_"
"location_synapse_admin_api_enabled: true"
)
raise ExitQWorker() # TODO
sys.exit(1)

logger.debug("JSON response: %s", response.json())

logger.debug("Response Status Code: %d", response.status_code)
if response.status_code not in req.success_codes:
if response.status_code not in request_config.success_codes:
with suppress(Exception):
if response.json()["errcode"] == "M_UNKNOWN_TOKEN":
logger.critical(
Expand All @@ -205,7 +215,7 @@ def _request(req: RequestBuilder) -> httpx.Response:
"and up-to-date. Your access-token will change every "
"time, you log out."
)
raise ExitQWorker() # TODO
sys.exit(1)
raise InternalResponseError(payload=response)

return response
Expand All @@ -232,10 +242,12 @@ async def _async_request(request_config: RequestBuilder) -> httpx.Response:
response: httpx.Response = await client.request(
method=request_config.method,
data=request_config.data,
json=request_config.json,
content=request_config.content,
url=str(request_config),
params=request_config.params,
headers=request_config.headers_with_auth,
timeout=request_config.timeout,
allow_redirects=False,
)

Expand All @@ -252,7 +264,10 @@ async def _async_request(request_config: RequestBuilder) -> httpx.Response:
raise ExitQWorker() # TODO
if response.status_code == 404:
logger.critical(
"You need to make sure, that your vars.yml contains the "
"The server returned an 404 error. This can have two causes. "
"The first one is, you try to request a ressource, which does not "
"exist. The second one is, your API endpoint is disabled."
"Make sure, that your vars.yml contains the "
"following excessive long line:\n\n"
"matrix_nginx_proxy_proxy_matrix_client_api_forwarded_"
"location_synapse_admin_api_enabled: true"
Expand Down
2 changes: 2 additions & 0 deletions matrixctl/handlers/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from types import TracebackType
from typing import NamedTuple

from paramiko import AutoAddPolicy
from paramiko import SSHClient
from paramiko.channel import ChannelFile

Expand Down Expand Up @@ -59,6 +60,7 @@ def __init__(
self.user: str = getuser() if user is None else user
self.__client: SSHClient = SSHClient()
self.__client.load_system_host_keys()
self.__client.set_missing_host_key_policy(AutoAddPolicy())
self.__connect()

def __connect(self) -> None:
Expand Down
Loading

0 comments on commit d6a15a9

Please sign in to comment.