Skip to content

Commit 794a083

Browse files
committed
Add IRC -> Matrix message redaction
1 parent 96d187f commit 794a083

File tree

3 files changed

+137
-1
lines changed

3 files changed

+137
-1
lines changed

lib/irc/handler.ex

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,27 @@ defmodule M51.IrcConn.Handler do
906906
{"TAGMSG", _} ->
907907
send_needmoreparams.()
908908

909+
{"REDACT", [channel, targetmsgid, reason | _]} ->
910+
send_redact(
911+
sup_pid,
912+
channel,
913+
Map.get(command.tags, "label"),
914+
targetmsgid,
915+
reason
916+
)
917+
918+
{"REDACT", [channel, targetmsgid | _]} ->
919+
send_redact(
920+
sup_pid,
921+
channel,
922+
Map.get(command.tags, "label"),
923+
targetmsgid,
924+
nil
925+
)
926+
927+
{"REDACT", _} ->
928+
send_needmoreparams.()
929+
909930
{"CHATHISTORY", ["TARGETS", _ts1, _ts2, _limit | _]} ->
910931
# This is mainly used for PMs, and we don't support those yet; so there
911932
# is little point in storing state to actually implement it
@@ -1377,6 +1398,61 @@ defmodule M51.IrcConn.Handler do
13771398
end
13781399
end
13791400

1401+
defp send_redact(sup_pid, channel, label, targetmsgid, reason) do
1402+
writer = M51.IrcConn.Supervisor.writer(sup_pid)
1403+
matrix_client = M51.IrcConn.Supervisor.matrix_client(sup_pid)
1404+
matrix_state = M51.IrcConn.Supervisor.matrix_state(sup_pid)
1405+
send = fn cmd -> M51.IrcConn.Writer.write_command(writer, cmd) end
1406+
1407+
# If the client provided a label, use it as txnId on Matrix's side.
1408+
# This way we can parse it when receiving the echo from Matrix's event
1409+
# stream instead of storing state.
1410+
# Otherwise, generate a random transaction id.
1411+
1412+
nicklist =
1413+
case M51.MatrixClient.State.room_from_irc_channel(matrix_state, channel) do
1414+
{_room_id, room} -> room.members |> Map.keys()
1415+
nil -> []
1416+
end
1417+
1418+
reason =
1419+
case reason do
1420+
nil ->
1421+
nil
1422+
1423+
reason ->
1424+
{reason, _formatted_reason} = M51.Format.irc2matrix(reason, nicklist)
1425+
reason
1426+
end
1427+
1428+
result =
1429+
M51.MatrixClient.Client.send_redact(
1430+
matrix_client,
1431+
channel,
1432+
label,
1433+
targetmsgid,
1434+
reason
1435+
)
1436+
1437+
case result do
1438+
{:ok, _event_id} ->
1439+
nil
1440+
1441+
{:error, error} ->
1442+
send.(%M51.Irc.Command{
1443+
source: "server.",
1444+
command: "FAIL",
1445+
params: [
1446+
"REDACT",
1447+
"UNKNOWN_ERROR",
1448+
channel,
1449+
targetmsgid,
1450+
"Error while redacting message: " <> Kernel.inspect(error)
1451+
]
1452+
})
1453+
end
1454+
end
1455+
13801456
defp close_connection(sup_pid) do
13811457
writer = M51.IrcConn.Supervisor.writer(sup_pid)
13821458
M51.IrcConn.Writer.close(writer)

lib/matrix_client/client.ex

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,40 @@ defmodule M51.MatrixClient.Client do
296296
end
297297
end
298298

299+
@impl true
300+
def handle_call({:send_redact, channel, label, event_id, reason}, _from, state) do
301+
%M51.MatrixClient.Client{
302+
state: :connected,
303+
irc_pid: irc_pid,
304+
raw_client: raw_client
305+
} = state
306+
307+
matrix_state = M51.IrcConn.Supervisor.matrix_state(irc_pid)
308+
309+
transaction_id = label_to_transaction_id(label)
310+
311+
reply =
312+
case M51.MatrixClient.State.room_from_irc_channel(matrix_state, channel) do
313+
nil ->
314+
{:reply, {:error, {:room_not_found, channel}}, state}
315+
316+
{room_id, _room} ->
317+
path =
318+
"/_matrix/client/r0/rooms/#{urlquote(room_id)}/redact/#{urlquote(event_id)}/#{urlquote(label)}"
319+
320+
body =
321+
case reason do
322+
reason when is_binary(reason) -> Jason.encode!(%{"reason" => reason})
323+
_ -> Jason.encode!({})
324+
end
325+
326+
case M51.Matrix.RawClient.put(raw_client, path, body) do
327+
{:ok, %{"event_id" => event_id}} -> {:ok, event_id}
328+
{:error, error} -> {:error, error}
329+
end
330+
end
331+
end
332+
299333
@impl true
300334
def handle_call({:get_event_context, channel, event_id, limit}, _from, state) do
301335
%M51.MatrixClient.Client{
@@ -543,13 +577,23 @@ defmodule M51.MatrixClient.Client do
543577
@doc """
544578
Sends the given event object.
545579
546-
If 'label' is not nil, it will be passed as a 'label' message tagt when
580+
If 'label' is not nil, it will be passed as a 'label' message tag when
547581
the event is seen in the event stream.
548582
"""
549583
def send_event(pid, channel, label, event_type, event) do
550584
GenServer.call(pid, {:send_event, channel, event_type, label, event}, @timeout)
551585
end
552586

587+
@doc """
588+
Asks the server to redact the event with the given id
589+
590+
If 'label' is not nil, it will be passed as a 'label' message tag when
591+
the event is seen in the event stream.
592+
"""
593+
def send_redact(pid, channel, label, event_id, reason) do
594+
GenServer.call(pid, {:send_redact, channel, label, event_id, reason}, @timeout)
595+
end
596+
553597
@doc """
554598
Returns events that happened just before or after the specified event_id.
555599

test/irc/handler_test.exs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,4 +1078,20 @@ defmodule M51.IrcConn.HandlerTest do
10781078

10791079
assert_line("BATCH :-#{batch_id}\r\n")
10801080
end
1081+
1082+
test "redact a message for no reason", %{handler: handler} do
1083+
do_connection_registration(handler)
1084+
1085+
send(handler, cmd("REDACT #existing_room:example.org $event1"))
1086+
1087+
assert_message({:send_redact, "#existing_room:example.org", nil, "$event1", nil})
1088+
end
1089+
1090+
test "redact a message for a reason", %{handler: handler} do
1091+
do_connection_registration(handler)
1092+
1093+
send(handler, cmd("REDACT #existing_room:example.org $event1 :spam"))
1094+
1095+
assert_message({:send_redact, "#existing_room:example.org", nil, "$event1", "spam"})
1096+
end
10811097
end

0 commit comments

Comments
 (0)