Skip to content

Commit

Permalink
Fix crash when WHOISing invalid MXID
Browse files Browse the repository at this point in the history
  • Loading branch information
progval committed Feb 9, 2024
1 parent 8cf8f99 commit 80dc1da
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 41 deletions.
90 changes: 50 additions & 40 deletions lib/irc/handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1102,51 +1102,61 @@ defmodule M51.IrcConn.Handler do
[_server, target | _] -> target
end

[local_name, hostname] = String.split(target, ":", parts: 2)
case String.split(target, ":", parts: 2) do
[_] ->
# return ERR_NOSUCHNICK
if target == "" || String.contains?(target, " ") do
send_numeric.("401", ["*", "No such nick"])
else
send_numeric.("401", [target, "No such nick"])
end

[member: memberships] = M51.MatrixClient.State.user(matrix_state, target)
[local_name, hostname] ->
[member: memberships] = M51.MatrixClient.State.user(matrix_state, target)

# TODO: pick the most common display name instead
gecos = target
# TODO: pick the most common display name instead
gecos = target

overhead = make_numeric.("353", [target, ""]) |> M51.Irc.Command.format() |> byte_size()
overhead =
make_numeric.("353", [target, ""]) |> M51.Irc.Command.format() |> byte_size()

first_commands = [
# RPL_WHOISUSER "<nick> <username> <host> * :<realname>"
make_numeric.("311", [target, local_name, hostname, "*", gecos])
]
first_commands = [
# RPL_WHOISUSER "<nick> <username> <host> * :<realname>"
make_numeric.("311", [target, local_name, hostname, "*", gecos])
]

channel_commands =
memberships
|> Map.keys()
|> Enum.map(fn room_id ->
M51.MatrixClient.State.room_irc_channel(matrix_state, room_id)
end)
|> Enum.sort()
|> M51.Irc.WordWrap.join_tokens(512 - overhead)
|> Enum.map(fn line ->
line = line |> String.trim_trailing()

if line != "" do
# RPL_WHOISCHANNELS "<nick> :[prefix]<channel>{ [prefix]<channel>}"
make_numeric.("319", [target, line])
end
end)
|> Enum.filter(fn line -> line != nil end)

last_commands = [
# RPL_WHOISSERVER "<nick> <server> :<server info>"
make_numeric.("312", [target, hostname, hostname]),
# RPL_WHOISACCOUNT "<nick> <account> :is logged in as"
make_numeric.("330", [target, target, "is logged in as"]),
# RPL_ENDOFWHOIS
make_numeric.("318", [target, "End of WHOIS"])
]

send_batch.(
Enum.concat([first_commands, channel_commands, last_commands]),
"labeled-response"
)
channel_commands =
memberships
|> Map.keys()
|> Enum.map(fn room_id ->
M51.MatrixClient.State.room_irc_channel(matrix_state, room_id)
end)
|> Enum.sort()
|> M51.Irc.WordWrap.join_tokens(512 - overhead)
|> Enum.map(fn line ->
line = line |> String.trim_trailing()

if line != "" do
# RPL_WHOISCHANNELS "<nick> :[prefix]<channel>{ [prefix]<channel>}"
make_numeric.("319", [target, line])
end
end)
|> Enum.filter(fn line -> line != nil end)

last_commands = [
# RPL_WHOISSERVER "<nick> <server> :<server info>"
make_numeric.("312", [target, hostname, hostname]),
# RPL_WHOISACCOUNT "<nick> <account> :is logged in as"
make_numeric.("330", [target, target, "is logged in as"]),
# RPL_ENDOFWHOIS
make_numeric.("318", [target, "End of WHOIS"])
]

send_batch.(
Enum.concat([first_commands, channel_commands, last_commands]),
"labeled-response"
)
end

{"BATCH", [first_param | params]} ->
{first_char, reference_tag} = String.split_at(first_param, 1)
Expand Down
14 changes: 13 additions & 1 deletion test/irc/handler_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ defmodule M51.IrcConn.HandlerTest do
assert_line("BATCH :-#{batch_id}\r\n")
end

test "WHOIS", %{handler: handler} do
test "WHOIS unknown user", %{handler: handler} do
do_connection_registration(handler)

send(handler, cmd("@label=l1 WHOIS unknown_user:example.com"))
Expand All @@ -855,6 +855,18 @@ defmodule M51.IrcConn.HandlerTest do
assert_line("BATCH :-#{batch_id}\r\n")
end

test "WHOIS non-MXID", %{handler: handler} do
do_connection_registration(handler)

send(handler, cmd("@label=l1 WHOIS not_enough_colons"))

assert_line("@label=l1 :server. 401 foo:example.org not_enough_colons :No such nick\r\n")

send(handler, cmd("@label=l1 WHOIS :with spaces"))

assert_line("@label=l1 :server. 401 foo:example.org * :No such nick\r\n")
end

test "MODE on user", %{handler: handler} do
do_connection_registration(handler)

Expand Down

0 comments on commit 80dc1da

Please sign in to comment.