Commit Graph

487 Commits

Author SHA1 Message Date
Simon Ser
f44e922c42 downstream: use ERR_BADCHANMASK for invalid channel name
It's more appropriate than ERR_NOSUCHCHANNEL.
2022-12-08 15:27:02 +01:00
Simon Ser
6d64c164a7 downstream: check channel name validity on JOIN
Avoid storing garbage in the DB.
2022-12-08 15:25:39 +01:00
Simon Ser
ec2c0685dd Add WHO cache
This adds a new field to upstreams, members, which is a casemapped map
of upstream users known to the soju. The upstream users known to soju
are: self, any monitored user, and any user with whom we share a
channel.

The information stored for each upstream user corresponds to the info
that can be returned by a WHO/WHOX command.

We build the upstream user information both incrementally, capturing
information contained in JOIN and AWAY messages; and with the bulk user
information contained in WHO replies we receive.

This lets us build a user cache that can then be used to return
synthetic WHO responses to later WHO requests by downstreams.

This is useful because some networks (eg Libera) heavily throttle WHO
commands, and without this cache, any downstream connecting would send 1
WHO command per channel, so possibly more than a dozen WHO commands,
which soju then forwarded to the upstream as WHO commands.

With this cache most WHO commands can be cached and avoid sending
WHO commands to the upstream.

In order to cache the "flags" field, we synthetize the field from user
info we get from incremental messages: away status (H/G) and bot status
(B). This could result in incorrect values for proprietary user fields.
Support for the server-operator status (*) is also not supported.

Of note is that it is difficult to obtain a user "connected server"
field incrementally, so clients that want to maximize their WHO cache
hit ratio can use WHOX to only request fields they need, and in
particular not include the server field flag.

Co-authored-by: delthas <delthas@dille.cc>
2022-12-01 15:50:33 +01:00
delthas
ac578823dc Fix clearing webpush targets after any MARKREAD
Previously, we would clear webpush targets after any MARKREAD.

Consider the following scenario (ignore any typos, this is crafted by
hand):

    <<< @time=2020-01-01T00:00:00Z PRIVMSG #foo :hi mark!
    <<< @time=2020-01-02T00:00:00Z PRIVMSG #foo :hi again mark!
    >>> MARKREAD #foo timestamp=2020-01-01T00:00:00Z
    >>> MARKREAD #foo timestamp=2020-01-02T00:00:00Z

The push target was previously cleared on the first MARKREAD, which
means that the second MARKREAD was never broadcast to Firebase, and all
devices would keep the "hi again mark!" notification indefinitely.

This changes the webpush target map so that we store a timestamp of the
last highlight we sent. We only clear the push target when sending a
MARKREAD that is at or after the last message.
2022-11-28 17:55:19 +01:00
delthas
897c21dbb4 Truncate message times to the second when using the FS message store
The FS message store truncates message times to the second.

This means that a message sent out as 2020-01-01T00:00:00.123Z could be
sent later as part of a CHATHISTORY batch as 2020-01-01T00:00:00.000Z,
which could cause issues in clients.

One such issue is a client sending a MARKREAD for
2020-01-01T00:00:00.000Z, with another client considering the
2020-01-01T00:00:00.123Z message it has as unread.

This fixes the issue by truncating all message times to the second when
using the FS message store.
2022-11-28 17:54:13 +01:00
Simon Ser
106d40dcd4 Upgrade to gopkg.in/irc.v4 2022-11-14 12:06:58 +01:00
Simon Ser
ea97b1a9bd Use ratified extended-monitor cap name for needAllDownstreamCaps
Fixes: 6ad3dcc396 ("Use ratified extended-monitor cap name")
2022-11-06 20:39:04 +01:00
Simon Ser
90be9a8ab9 downstream: stop sending HTTP OPTIONS request on WEBPUSH REGISTER
We were sending a test notification later anyways. Let's just do
that to check that the endpoint accepts our messages.
2022-09-30 12:20:07 +02:00
Simon Ser
c3ab11de4e downstream: drop downstreamConn.unmarshalEntity{,Network} 2022-09-26 16:57:05 +02:00
Simon Ser
8a2f544806 downstream: drop downstreamConn.marshalEntity
This is a no-op.
2022-09-26 16:57:05 +02:00
Simon Ser
31957a9ac4 downstream: drop downstreamConn.marshalMessage
It's a no-op.
2022-09-26 16:57:05 +02:00
Simon Ser
25257b8892 downstream: drop downstreamConn.marshalUserPrefix
This is now a no-op.
2022-09-26 16:57:05 +02:00
Simon Ser
00919e9412 downstream: drop downstreamConn.unmarshalText
It's unused.
2022-09-26 16:57:05 +02:00
Simon Ser
eba7aa38d2 downstream: drop downstreamConn.isMultiUpstream
This is now always false.
2022-09-26 16:57:05 +02:00
Simon Ser
1ea3a19403 downstream: refuse to enable multi-upstream mode
References: https://todo.sr.ht/~emersion/soju/125
2022-09-26 16:57:04 +02:00
Simon Ser
c5f6a41d6c downstream: remove outdated Web Push TODO
We already do that.
2022-09-16 18:58:42 +02:00
Simon Ser
bb868eae82 downstream: fix CHATHISTORY LATEST without a bound
Fixes: 5e56cc30c5 ("downstream: fix inverted range in CHATHISTORY LATEST with a timestamp")
2022-09-16 18:55:31 +02:00
Simon Ser
5b10348957 downstream: don't echo back SASL mechanism
Some clients will queue up multiple AUTHENTICATE commands without
waiting for a reply to avoid some roundtrips. However that means
the traffic looks like so:

    AUTHENTICATE <mechanism>
    AUTHENTICATE <base64 blob containing credentials>

soju will fail the first command, and will behave as if no SASL
authentication was in progress when interpreting the second one.
This means we'll echo back the security-sensitive base64 blob to
the client in the error message, which is definitely not great.

Stop doing that.
2022-09-12 21:42:03 +02:00
Simon Ser
f4af7975d3 Pass-through ISUPPORT LINELEN
Can be used by the server to indicate support for a greater message
size limit.
2022-08-28 18:53:41 +02:00
Ember Sawady
57584c08ed Fix NICK on upstreams supporting MONITOR
Previously, uc.network.Network.Nick wasn't successfully updated on
downstream NICK. This would cause soju to immediately switch back to the
old nick when the upstream supported MONITOR, so long as the network had
a nick configured as of initialization.

In addition, stop monitoring our desired nick once we've successfully
switched to it once, in order to not immediately undo server-induced
nick changes.
2022-08-23 09:39:24 +02:00
Petr Ročkai
5e56cc30c5 downstream: fix inverted range in CHATHISTORY LATEST with a timestamp 2022-08-17 19:43:01 +02:00
Simon Ser
6fa8a1f30a downstream: add hard limit on Web Push subscriptions
Each subscription comes with the cost of a HTTP request when
broadcasting a message.
2022-08-17 17:08:23 +02:00
Simon Ser
cffdbc16b4 downstream: break findWebPushSubscription in two functions
We'll use that to count the number of existing subscriptions in
the next commit.
2022-08-17 17:04:11 +02:00
Simon Ser
65f0b2367e Broadcast Web Push subscriptions in a new goroutine 2022-08-17 16:09:12 +02:00
Simon Ser
0ef8b7d4c8 downstream: re-format doc comment with Go 1.19 style
We can use lists now.
2022-08-05 18:37:32 +02:00
Simon Ser
f37aedea79 downstream: reply to INFO 2022-07-14 15:51:26 +02:00
gildarts
48960a2992 database: upgrade bcrypt cost as needed
Closes: https://todo.sr.ht/~emersion/soju/136
2022-07-12 18:52:49 +02:00
Simon Ser
c69ea81999 downstream: fix downstream check for draft/read-marker
`dc` is the source connection, `d` is the destination for the
broadcast.

Fixes: 7e21e79eab ("downstream: fix MARKREAD/READ command name in broadcast")
2022-07-12 17:04:46 +02:00
Simon Ser
1e78e3e4b0 dowstream: remove noop WEBPUSH REGISTER
We still want to update the updated_at column when a client
refreshes the subscription.
2022-07-11 22:54:51 +02:00
Simon Ser
4e683af535 Aggregate AWAY status from all connected clients
Closes: https://todo.sr.ht/~emersion/soju/200
2022-07-11 19:36:12 +02:00
Simon Ser
84188ba644 downstream: relay SETNAME with upstreamConn.SendMessageLabeled
This makes it so any errors are only relayed to this downstream
connection.

The upstream handler for SETNAME handles the broadcasting to all
downstream connections already.
2022-07-08 18:17:24 +02:00
Simon Ser
b1b4541a53 downstream: simplify NICK handling when disconnected 2022-07-08 18:14:10 +02:00
Simon Ser
dc0a847240 Add per-user default nickname
The soju username is immutable. Add a separate nickname setting so
that users can change their nickname for all networks.

References: https://todo.sr.ht/~emersion/soju/110
2022-07-08 18:01:05 +02:00
Simon Ser
14cbd63412 Send MARKREAD push notifications
Allows clients to dismiss notifications when another client marks
the conversation as read.
2022-07-08 16:55:29 +02:00
Simon Ser
7e21e79eab downstream: fix MARKREAD/READ command name in broadcast
We wouldn't send a MARKREAD message to draft/read-marker downstreams
when receiving a READ command.
2022-07-08 15:17:30 +02:00
Simon Ser
0d44413e85 upstream: drop upstreamConn.nickCM
Removes an unnecessary source of truth.
2022-07-08 14:52:10 +02:00
Simon Ser
e2e3e2731b Fix draft/read-marker entry in permanentDownstreamCaps
Oops.

Fixes: 71d639699e ("Add support for draft/read-marker")
2022-07-01 15:58:11 +02:00
Simon Ser
71d639699e Add support for draft/read-marker
References: https://github.com/ircv3/ircv3-specifications/pull/489
2022-07-01 13:33:28 +02:00
Simon Ser
f0db261fc0 database: add missing user column to WebPushSubscription table
Some WebPushSubscription entries aren't tried to a network, in
which case the "network" column is NULL. But then all users share
the same row. Oops.

Fortunately network-less subscriptions aren't used for anything
yet, they're just stored. So the impact should be minimal.
2022-06-16 19:33:39 +02:00
Simon Ser
de0992d41e downstream: fix panic in findWebPushSubscription for unbound conns
This code has been missed when adding webpush support for downstream
connections without an upstream network bound.
2022-06-15 09:09:28 +02:00
Simon Ser
3863b8cb6b Add webpush extension
References: https://github.com/ircv3/ircv3-specifications/pull/471
Co-authored-by: delthas <delthas@dille.cc>
2022-06-14 16:16:12 +02:00
Simon Ser
fe40c51ff0 database: add User.{Check,Set}Password 2022-06-08 13:27:33 +02:00
Simon Ser
09f2cf8489 Don't provide name in channel casemapMap Set and ForEach
The name is already provided in the struct.
2022-06-06 10:05:31 +02:00
Simon Ser
657e25b25c Make casemapMap more type-safe
In addition to a type-safe getter, also define type-safe setters
and iterators.

References: https://lists.sr.ht/~emersion/soju-dev/patches/32777
2022-06-06 09:58:39 +02:00
Simon Ser
c8f9728ff6 Drop size arg from newCasemapMap
It's unused.
2022-06-06 09:23:17 +02:00
Simon Ser
22b235602b Add soju.im/account-required
References: https://github.com/ircv3/ircv3-specifications/pull/492
2022-06-04 10:52:28 +02:00
Simon Ser
3c5e603192 Remove bridge.go
All of its functions belong to downstream.go.
2022-05-30 09:51:36 +02:00
Simon Ser
da8f626e51 xirc: add GenerateSASL 2022-05-30 09:41:47 +02:00
Simon Ser
f3b06f4236 xirc: move over WHOX helpers 2022-05-29 18:33:29 +02:00
Simon Ser
9b37bd2eaa xirc: move over CapRegistry 2022-05-29 18:33:22 +02:00
Simon Ser
fa6f52ed08 xirc: encode tokens in GenerateIsupport 2022-05-29 18:24:10 +02:00
Simon Ser
c10d382a7d xirfc: move over message generation functions 2022-05-29 17:57:21 +02:00
Simon Ser
c50fb4a26d xirc: move command constants over 2022-05-09 17:18:51 +02:00
Simon Ser
620a8789b0 Add msgstore package 2022-05-09 16:25:57 +02:00
Simon Ser
b92afa7cca Introduce an xirc package 2022-05-09 16:15:00 +02:00
Simon Ser
89412187d4 msgstore: rename searchMessageOptions, export fields
Preparation for splitting msgstore into a separate package.
2022-05-09 15:44:41 +02:00
Simon Ser
f508d36c38 msgstore: add loadMessageOptions
A struct containing common parameters for all messageStore.Load*
functions returning messages.
2022-05-09 15:36:39 +02:00
Simon Ser
3a7dee8128 Introduce a database package 2022-05-09 15:08:04 +02:00
Simon Ser
d37f946e83 downstream: fix setting tls=0 in bouncer-networks
The old code resulted in URLs like "irc+insecure://0".
2022-05-03 10:43:02 +02:00
Simon Ser
2e5474d05a downstream: improve error message on unrecognized message 2022-04-27 19:05:01 +02:00
Simon Ser
f3932ab500 Drop user.forEachDownstream
It's just a for loop.
2022-04-15 10:32:28 +02:00
delthas
b790db1423 Keep batch tag for downstreams with batch cap
On upstreams without message-tags support, we do not advertise
message-tags anymore. Still, we want to send the batch tag when the
client explicitly requested it.

This fixes a critical issue where we drop the batch tag on chathistory
messages for upstreams that do not support message-tags.
2022-04-12 17:58:36 +02:00
delthas
683cfe0615 Add support for the SEARCH extension 2022-04-12 17:58:16 +02:00
delthas
b67b9b3cd2 Enable message-tags only when all upstreams support it
Previously, we would always advertise mesasge-tags. This made
downstreams believe they could send TAGMSG to the upstream, even though
the upstream did not support it.
2022-04-12 12:41:50 +02:00
delthas
abe5291b62 Add support for the upstream echo-message capability
This adds support for upstream echo-message. This capability is
enabled when the upstream supports labeled-response.

When it is enabled, we don't echo downstream messages in the downstream
handler, but rather wait for the upstream to echo it, to produce it to
downstreams.

When it is disabled, we keep the same behaviour as before: produce the
message to all downstreams as soon as it is received from the
downstream.

In other words, the main functional difference is that when the upstream
supports labeled-response, the client will now receive an echo for its
messages when the server acknowledges them, rather than when soju acks
them.

Additionally, uc.produce was refactored to take an ID rather than a
downstream.
2022-04-11 17:27:47 +02:00
delthas
f7a468194d bouncer-networks: Add a read-only error attribute
This is useful for clients to display additional info abotu why a
network is disconnected.
2022-04-11 08:38:31 +02:00
delthas
d8ca6d2222 Enable resetting a BOUNCER NETWORK port
When a client sends BOUNCER CHANGENETWORK with no value (or an empty
port value), this means it wants to reset the port value to its default
value.

Previously we considered an empty port as an actual valid, empty port
value, which would then be used to connect to the server (dial
'example.com:' (ie 'example.com:0'), which failed.
2022-04-10 18:12:12 +02:00
Simon Ser
793ac29571 downstream: use upstream user/host for echo message 2022-04-05 10:09:49 +02:00
Simon Ser
9513c28208 downstream: unify PRIVMSG/NOTICE and TAGMSG codepaths
They are nearly identical, the only difference is that TAGMSG has
no text parameter.

Inspired from a patch from delthas:
https://lists.sr.ht/~emersion/soju-dev/patches/30651
2022-04-05 10:09:29 +02:00
Simon Ser
846c99dedc Queue WHOIS commands
This avoids having more than one in flight at a time (avoids
hitting rate limits a bit) and routes back replies to the correct
downstream connection (even if labeled-response isn't supported).

Closes: https://todo.sr.ht/~emersion/soju/193
2022-04-04 09:58:26 +02:00
Simon Ser
303c663d02 Refuse to change nick on bouncer connection
Also simplify the code.

Closes: https://todo.sr.ht/~emersion/soju/192
2022-04-01 14:55:36 +02:00
Simon Ser
29b1e6f47b downstream: update user realname on SETNAME 2022-03-30 17:51:04 +02:00
Simon Ser
d7b5f5d12c downstream: set realname for network-less connections
Send the user-wide realname config. We still need to handle SETNAME
properly.
2022-03-30 14:17:09 +02:00
Simon Ser
0ec3e63ace downstream: send RPL_ENDOFWHO on unmarshalEntity error
Also remove a couple of outdated comments.
2022-03-23 19:15:52 +01:00
Simon Ser
44efe37292 downstream: clarify "user not active" error message 2022-03-23 13:11:37 +01:00
Simon Ser
43371bf347 Add the soju.im/no-implicit-names extension
References: https://github.com/ircv3/ircv3-ideas/issues/87
2022-03-22 21:03:20 +01:00
Simon Ser
128aefcc50 downstream: strip back "*" prefix 2022-03-21 17:16:02 +01:00
Simon Ser
8e4c8f7e5a downstream: copy message when degrading extended-join
Otherwise we mutate the input argument and loops over downstream
connections to send messages will be messed up.
2022-03-21 17:13:55 +01:00
Simon Ser
883683c0b7 downstream: always populate downstreamConn.username
This ensures we don't send a prefix without a username in it.
2022-03-21 16:37:04 +01:00
Simon Ser
069625d30d downstream: rejigger hostname logic in newDOwnstreamConn
I find it easier to read this way.
2022-03-21 16:33:58 +01:00
Simon Ser
e403b88a3d Add support for chghost 2022-03-21 16:30:58 +01:00
Simon Ser
78d9a84a6f Add support for RPL_VISIBLEHOST 2022-03-21 16:09:45 +01:00
Simon Ser
b0dbb3cef1 downstream: explain when downstreamConn.sasl is nil 2022-03-21 15:11:43 +01:00
Simon Ser
70ba7032f1 downstream: move negotiatingCaps to downstreamRegistration
This field is only relevant during connection registration.
2022-03-21 15:09:31 +01:00
Simon Ser
884bfec6a6 downstream: improve grouping of downstreamConn fields 2022-03-21 15:08:12 +01:00
Simon Ser
b3425ba1a3 downstream: process BOUNCER BIND in downstreamConn.welcome
This allows clients to send BOUNCER BIND before SASL auth, or to
use BOUNCER BIND with PASS.
2022-03-21 15:02:54 +01:00
Simon Ser
2c691d012d downstream: reject negative or zero network IDs in parseBouncerNetID 2022-03-21 15:00:30 +01:00
Simon Ser
d9468b983f downstream: move multi-upstream name handling to loadNetwork 2022-03-21 14:54:23 +01:00
Simon Ser
bed50c10ce downstream: ignore nickname during connection registration
Just force-set the nickname and completely disregard what the client
sets during connection registration. Clients must discover their
effective nickname via RPL_WELCOME.
2022-03-21 14:54:21 +01:00
delthas
2ac9bd9c94 Require an explicit * network suffix for multi-upstream
Most users will connect to their server with `<username>` as their
username in order to configure their upstreams.

Multi-upstream can be unintuitive to them and should not be enabled on
that first connection that is usually used for upstream configuration.

Multi-upstream is instead a power-user feature that should be explicitly
enabled with a specific network suffix.

We reserve the network suffix `*` and use it a special case to mean that
it requests multi-upstream mode.
2022-03-21 09:56:20 +01:00
Simon Ser
744c6e3f6d Enable bot mode for BouncerServ
See [1] for details.

[1]: https://ircv3.net/specs/extensions/bot-mode
2022-03-16 18:35:48 +01:00
Simon Ser
777adbd5e1 downstream: improve ERR_ERRONEUSNICKNAME message a bit 2022-03-16 12:33:23 +01:00
Simon Ser
35b09f069c downstream: atomically ack/nak capabilities 2022-03-14 19:30:29 +01:00
Simon Ser
6e094b1099 Use capRegistry for upstreamConn 2022-03-14 19:25:49 +01:00
Simon Ser
74fd506fef Use capRegistry for downstreamConn 2022-03-14 19:25:49 +01:00
delthas
9376c8885c downstream: Enable handling READ when upstream is disconnected
Previously, when we sent READ for an upstream which was disconnected,
we would fail with an error. This is because we called unmarshalEntity,
which checked that the upstream was in the connected status.

But we don't need to be connected to update the READ timestamp, this is
a purely offline (wrt the upstream) operation.

This simply switches the call from unmarshalEntity to
unmarshalEntityNetwork to fix the issue.
2022-03-08 22:35:46 +01:00
Simon Ser
fdf9727600 Mark BouncerServ as online in MONITOR, don't forward to upstream 2022-03-08 21:29:04 +01:00
Simon Ser
d8f5f8481f downstream: set case-mapping for monitored 2022-03-08 21:28:43 +01:00
Simon Ser
2060ae05cf downstream: drop delivery receipts when client supports chathistory
When the client supports draft/chathistory, no need to request
delivery receipts via PING messages. Let's just not leave delivery
receipts alone. They'll go stale but should be never used (or used
by a non-chathistory client).
2022-03-08 16:45:45 +01:00
Simon Ser
a438c34489 downstream: disallow '.' in nicknames
See [1] and [2].

[1]: https://github.com/ircdocs/modern-irc/pull/148
[2]: eff6dd242b/irc/strings.go (L29)
2022-03-03 10:54:21 +01:00