Commit graph

301 commits

Author SHA1 Message Date
Simon Ser 16e43ee3a3 upstream: don't populate time tag for numerics
Allows us to save a few bytes, e.g. in WHO replies.
2022-03-22 21:14:02 +01:00
Simon Ser 09513e63fe Remove unnecessary zero initialization 2022-03-22 21:10:06 +01:00
Simon Ser 5defd29509 Ensure all incoming messages have a prefix set
Per the spec:

> If the source is missing from a message, it’s is assumed to have originated
> from the client/server on the other end of the connection the message was
> received on.
2022-03-21 17:01:15 +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 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
Simon Ser fdf9727600 Mark BouncerServ as online in MONITOR, don't forward to upstream 2022-03-08 21:29:04 +01:00
Simon Ser 9a79c66921 upstream: use network case-mapping in updateMonitor
We were using the downstream case-mapping.
2022-03-08 21:27:43 +01:00
Simon Ser 1a56b2f658 Introduce formatServerTime
It's too easy to forget to convert to UTC.
2022-02-16 14:45:09 +01:00
delthas cae248f672 Add support for the wip soju.im/read capability and READ command
READ lets downstream clients share information between each other about
what messages have been read by other downstreams.

Each target/entity has an optional corresponding read receipt, which is
stored as a timestamp.

- When a downstream sends:
  READ #chan timestamp=2020-01-01T01:23:45.000Z
  the read receipt for that target is set to that date
- soju sends READ to downstreams:
  - on JOIN, if the client uses the soju.im/read capability
  - when the read receipt timestamp is set by any downstream

The read receipt date is clamped by the previous receipt date and the
current time.
2022-02-11 19:41:46 +01:00
Simon Ser b1a83529e1 Fix flags variable name in RPL_WHOREPLY handler
This param doesn't contain modes, it contains user flags (such as
H/G for away status).
2022-02-09 15:20:32 +01:00
Simon Ser e72c896bb4 Add context to upstreamConn.register 2022-02-08 16:38:34 +01:00
Simon Ser 375ac53f74 Add context to upstreamConn.runUntilRegistered 2022-02-08 16:37:31 +01:00
Simon Ser de7d1f7784 Add context to upstreamConn.handleCapAck 2021-12-10 12:28:16 +01:00
Simon Ser fe564af756 Handle upstream multi-line SASL
References: https://todo.sr.ht/~emersion/soju/173
2021-12-10 10:46:41 +01:00
Simon Ser e397cc2a1f Block RPL_{CREATIONTIME,TOPICWHOTIME} for detached channels
Closes: https://todo.sr.ht/~emersion/soju/132
2021-12-09 12:12:20 +01:00
Simon Ser 66aea1b4a2 Add context to {conn,upstreamConn}.SendMessage
This avoids blocking on upstream message rate limiting for too
long.
2021-12-08 18:03:40 +01:00
Simon Ser b6c47a517c Use more descriptive errors when aborting pending commands 2021-12-06 22:33:50 +01:00
Simon Ser d7f7e351af Improve msgStore.Append log message wording 2021-12-06 18:46:10 +01:00
Simon Ser f881a42b4b Stop incrementing hopcount in RPL_WHOREPLY
It's extra code for something clients should ignore because it's
unreliable and useless.
2021-12-06 18:08:53 +01:00
Simon Ser 548b1c6930 Read nickname from RPL_WELCOME
References: https://github.com/ircdocs/modern-irc/pull/146
2021-12-06 17:58:54 +01:00
Simon Ser 1c285a1b72 Fallback to alt nick
If the nickname we want is taken, fallback to another one by
appending underscores. Use MONITOR to figure out when we can request
our desired nick again.

Closes: https://todo.sr.ht/~emersion/soju/35
2021-12-04 20:07:23 +01:00
Simon Ser f2a28f6e22 Avoid forwarding MONITOR requests if upstream doesn't support it
Clients aren't supposed to do this, but in case they do, let's
send them an error.
2021-12-04 19:29:39 +01:00
Simon Ser 04b0c2fd6b Add context to upstreamConn.handleMessage 2021-12-02 23:27:12 +01:00
Simon Ser a413681253 Cancel pending commands on downstream disconnect
If a client queues a high number of commands and then disconnects,
remove all of the pending commands. This avoids unnecessarily
sending commands whose results won't be used.
2021-12-02 19:29:44 +01:00
Simon Ser 1620344f0a Mark ACCOUNT_REQUIRED error as permanent connection failure
There's no point in retrying to connect in this case.
2021-12-02 17:58:56 +01:00
Simon Ser fd9a935f3e Don't retry connecting on permanent failure
Closes: https://todo.sr.ht/~emersion/soju/164
2021-12-02 17:33:11 +01:00
Simon Ser 73287f242e Add context to connectToUpstream 2021-12-02 10:53:43 +01:00
Simon Ser 23fd727618 Add support for draft/account-registration proxying
This adds support for the draft/account-registration extension [1].
This allows downstreams to register on upstream networks.

[1]: https://ircv3.net/specs/extensions/account-registration
2021-11-30 12:02:54 +01:00
Simon Ser e3d7c33bcd Remove sasl cap after registration if network doesn't support it
This will stop clients from trying to issue AUTHENTICATE requests
after connection registration.
2021-11-21 16:28:38 +01:00
Simon Ser 313c6e7f97 Add support for post-connection-registration upstream SASL auth
Once the downstream connection has logged in with their bouncer
credentials, allow them to issue more SASL auths which will be
redirected to the upstream network. This allows downstream clients
to provide UIs to login to transparently login to upstream networks.
2021-11-21 16:10:54 +01:00
Simon Ser c2a5461cb8 Use RPL_LOGGEDIN/OUT to mirror upstream status
This will allow clients to properly show/hide UI to login and
register.
2021-11-19 19:21:48 +01:00
Simon Ser c6f5508765 Add missing account-notify to permanentUpstreamCaps 2021-11-19 11:55:22 +01:00
Simon Ser 5a5c93a756 Add message counter metrics 2021-11-17 15:58:19 +01:00
Simon Ser 55840312b4 Add per-user IP addresses
The new upstream-user-ip directive allows bouncer operators to
assign one IP address per user.
2021-11-17 15:07:58 +01:00
delthas 840d142f1c Add support for draft/extended-monitor
References: https://github.com/ircv3/ircv3-specifications/pull/466
2021-11-15 14:38:19 +01:00
Simon Ser 5d46dd72a4 Add support for MONITOR
Add support for MONITOR in single-upstream mode.

Each downstream has its own set of monitored targets. These sets
are merged together to compute the MONITOR commands to send to
upstream.

Each upstream has a set of monitored targets accepted by the server
alongside with their status (online/offline). This is used to
directly send replies to downstreams adding a target another
downstream has already added, and send MONITOR S[TATUS] replies.

Co-authored-by: delthas <delthas@dille.cc>
2021-11-15 14:34:04 +01:00
Simon Ser 0b6ff2e61a Add a queue for WHO commands
This has the following upsides:

- We can now routes WHO replies to the correct client, without
  broadcasting them to everybody.
- We are less likely to hit server rate limits when multiple downstreams
  are issuing WHO commands at the same time.
2021-11-09 22:09:17 +01:00
Simon Ser 0c360d24c5 Remove support for mixed multi-upstream LIST
Multi-upstream connections can still send LIST commands with a
network suffix.
2021-11-09 21:32:26 +01:00
Simon Ser 659083c781 Fix upstream USER command when both username and nick are empty 2021-11-07 18:33:59 +01:00
Simon Ser 2b4f0a870f msgstore: take Network as arg instead of network
The message stores don't need to access the internal network
struct, they just need network metadata such as ID and name.

This can ease moving message stores into a separate package in the
future.
2021-11-03 16:37:01 +01:00
Simon Ser a6aa7f0008 Make Network.Nick optional
Make Network.Nick optional, default to the user's username. This
will allow adding a global setting to set the nickname in the
future, just like we have for the real name.

References: https://todo.sr.ht/~emersion/soju/110
2021-11-02 23:33:17 +01:00
Simon Ser 241e27b00e Add support for WHOX
This adds support for WHOX, without bothering about flags and mask2
because Solanum and Ergo [1] don't support it either.

The motivation is to allow clients to reliably query account names.

It's not possible to use WHOX tokens to route replies to the right
client, because RPL_ENDOFWHO doesn't contain it.

[1]: https://github.com/ergochat/ergo/pull/1184

Closes: https://todo.sr.ht/~emersion/soju/135
2021-11-02 18:25:43 +01:00
Simon Ser aa407a46e6 Get rid of io.EOF errors in logs
Closes: https://todo.sr.ht/~emersion/soju/150
2021-10-29 16:03:04 +02:00
Simon Ser 9ec1f1a5b0 Add context args to Database interface
This is a mecanical change, which just lifts up the context.TODO()
calls from inside the DB implementations to the callers.

Future work involves properly wiring up the contexts when it makes
sense.
2021-10-18 19:15:15 +02:00
Simon Ser 324d0fb0ac Unify away-notify and account-notify handling 2021-10-17 21:54:18 +02:00
Simon Ser 455fef2421 Add support for account-notify 2021-10-17 21:54:18 +02:00
Simon Ser a14f646135 Add per-user realname setting
This allows users to set a default realname used if the per-network
realname isn't set.

A new "user update" command is introduced and can be extended to edit
other user properties and other users in the future.
2021-06-25 20:33:13 +02:00
Simon Ser d7b1c5a9a2 Allow admins to broadcast message to all bouncer users
Typically done via:

    /notice $<bouncer> <message>

Or, for a connection not bound to a specific network:

    /notice $* <message>

The message is broadcast as BouncerServ, because that's the only
user that can be trusted to belong to the bouncer by users. Any
other prefix would conflict with the upstream network.
2021-06-23 19:23:09 +02:00
Simon Ser fb50d70b70 Forward LUSERS and STATS messages after initial registration 2021-06-23 11:45:14 +02:00
Simon Ser b609b86f97 Add support for account-tag 2021-06-14 21:44:38 +02:00
Gregory Anders 0e9ef1f97c Forward user mode changes in single-upstream mode
References: https://todo.sr.ht/~emersion/soju/20
2021-06-10 11:17:00 +02:00
Gregory Anders 2fe0a57e43 Forward MOTD messages downstream
The first MOTD upon connection is ignored, but subsequent MOTD messages
(requested by the "MOTD" message from the client, typically using a
/motd command) are forwarded.
2021-06-09 21:29:36 +02:00
Simon Ser 47c514a9cf Add support for IRCv3 setname
References: https://todo.sr.ht/~emersion/soju/41
2021-05-25 20:24:45 +02:00
Hubert Hirtz 03288d16f1 Don't forward label tags
We don't want to have the label tag when calling uc.produce, otherwise
downstream will end up with junk labels.
2021-05-23 12:32:27 +02:00
Hubert Hirtz 0f6bac30b8 Drop TAGMSG in detached channels
- Do not relay TAGMSG as notices,
- Do not reattach when a TAGMSG is received,
- Do not reset the detach timer when a TAGMSG is received.
2021-04-20 16:17:28 +02:00
Simon Ser 0d6d297027 Add user prefix to upstream logger 2021-04-13 20:16:37 +02:00
Simon Ser a2c207d357 Relay detached channel backlog as BouncerServ NOTICE if necessary
Instead of ignoring detached channels wehn replaying backlog,
process them as usual and relay messages as BouncerServ NOTICEs
if necessary. Advance the delivery receipts as if the channel was
attached.

Closes: https://todo.sr.ht/~emersion/soju/98
2021-04-13 19:11:05 +02:00
Simon Ser 76e332b50a Move isHighlight to irc.go 2021-04-13 18:54:58 +02:00
Simon Ser 1e4ff49472 Save delivery receipts in DB
This avoids loosing history on restart for clients that don't
support chathistory.

Closes: https://todo.sr.ht/~emersion/soju/80
2021-03-31 18:04:13 +02:00
Simon Ser 5e11e717f1 Rename user.clients to clientNames
This doesn't contain anything other than just the names. Make this
clearer.
2021-03-30 12:44:56 +02:00
Simon Ser ecf35187fa Make NickServ detection casemapping-aware 2021-03-30 12:28:45 +02:00
Simon Ser 3237bde9f3 Introduce deliveredStore
This hides the double-map complexity behind a dedicated type.
2021-03-29 17:49:50 +02:00
Simon Ser 55274d7213 Move network.clients to user
No need to have this list per-network.
2021-03-29 16:58:56 +02:00
Simon Ser 5a899abaab Simplify network.offlineClients
Replace it with a list of all clients (online or offline).
2021-03-29 16:55:57 +02:00
Simon Ser 6e5a307dc7 Introduce deliveredClientMap
Adds more semantics to map[string]string. Simplifies the complicated
mapStringStringCasemapMap type.
2021-03-26 11:21:14 +01:00
Hubert Hirtz bdd0c7bc06
Implement casemapping
TL;DR: supports for casemapping, now logs are saved in
casemapped/canonical/tolower form
(eg. in the #channel directory instead of #Channel... or something)

== What is casemapping? ==

see <https://modern.ircdocs.horse/#casemapping-parameter>

== Casemapping and multi-upstream ==

Since each upstream does not necessarily use the same casemapping, and
since casemappings cannot coexist [0],

1. soju must also update the database accordingly to upstreams'
   casemapping, otherwise it will end up inconsistent,
2. soju must "normalize" entity names and expose only one casemapping
   that is a subset of all supported casemappings (here, ascii).

[0] On some upstreams, "emersion[m]" and "emersion{m}" refer to the same
user (upstreams that advertise rfc1459 for example), while on others
(upstreams that advertise ascii) they don't.

Once upstream's casemapping is known (default to rfc1459), entity names
in map keys are made into casemapped form, for upstreamConn,
upstreamChannel and network.

downstreamConn advertises "CASEMAPPING=ascii", and always casemap map
keys with ascii.

Some functions require the caller to casemap their argument (to avoid
needless calls to casemapping functions).

== Message forwarding and casemapping ==

downstream message handling (joins and parts basically):
When relaying entity names from downstreams to upstreams, soju uses the
upstream casemapping, in order to not get in the way of the user.  This
does not brings any issue, as long as soju replies with the ascii
casemapping in mind (solves point 1.).

marshalEntity/marshalUserPrefix:
When relaying entity names from upstreams with non-ascii casemappings,
soju *partially* casemap them: it only change the case of characters
which are not ascii letters.  ASCII case is thus kept intact, while
special symbols like []{} are the same every time soju sends them to
downstreams (solves point 2.).

== Casemapping changes ==

Casemapping changes are not fully supported by this patch and will
result in loss of history.  This is a limitation of the protocol and
should be solved by the RENAME spec.
2021-03-24 18:15:52 +01:00
Simon Ser e35a116188 Don't update downstream caps in upstream RPL_WELCOME handler
Prior to being registered, upstreamConn.handleMessage doesn't run
in the user goroutine, it runs in a goroutine specific to the
network. Thus we shouldn't access any user data structure from
there.

downstreamConn.updateSupportedCaps is already called from the
eventUpstreamConnected handler in user.run, the call being removed
was unnecessary.

Closes: https://todo.sr.ht/~emersion/soju/108
2021-03-16 18:25:21 +01:00
Simon Ser 384075a6ed Don't store history for NickServ
Closes: https://todo.sr.ht/~emersion/soju/104
2021-03-16 09:54:29 +01:00
Simon Ser fa047123b9 Passthrough some ISUPPORT tokens 2021-03-15 23:41:37 +01:00
Simon Ser 3f005d481d Properly handle all ISUPPORT negations 2021-03-15 23:11:42 +01:00
Simon Ser 62d4bf2813 Use upstream ISUPPORT map for NETWORK 2021-03-15 23:08:19 +01:00
Simon Ser 2992ff79c4 Maintain state for upstream ISUPPORT 2021-03-15 23:06:36 +01:00
Simon Ser ff2cd9423f Simplify if block in ISUPPORT handler 2021-03-15 22:54:32 +01:00
Simon Ser ffd142f8dd Extract ISUPPORT CHANMODES/PREFIX to separate functions 2021-03-15 22:53:46 +01:00
Simon Ser d54c8c1122 Add Network.{URL,GetUsername,GetRealname}
Just a bunch of helpers that can be re-used.
2021-03-09 18:55:34 +01:00
Simon Ser 0954c7da79
Add irc to ALPN protocols
The new ALPN token has been approved [1]. We can start using it now.

[1]: https://mailarchive.ietf.org/arch/msg/tls-reg-review/i8YyT82XUtEgR-oXMG3sbyWYT8E/
2021-02-24 19:41:12 +01:00
Hubert Hirtz 6a1a05b1d4 if true return true else return false
Trivial improvement
2021-02-18 09:40:51 +01:00
Simon Ser 7e39f6d663 Rename network.history to network.delivered
"History" is over-loaded with e.g. CHATHISTORY support.
2021-02-10 11:31:34 +01:00
Hubert Hirtz 5aa15d5628 Request invite-notify to upstreams
... and do not forward INVITEs to downstreams that do not support the
capability.

The downstream capability can be permanent because there is no way for a
client to get the list of people invited to a channel, thus no state can
be corrupted.
2021-01-31 22:18:51 +01:00
Simon Ser 62f1207437 Forward ISUPPORT NETWORK token 2021-01-22 12:00:38 +01:00
Hubert Hirtz a747c732c0
Don't forward batch tags
We don't want to have the batch tag when calling uc.produce, otherwise
downstream will end up with junk batch ids.
2021-01-10 22:48:08 +01:00
delthas a76b22bf29 Add customizable auto-detaching, auto-reattaching, relaying.
This uses the fields added previously to the Channel struct to implement
the actual detaching/reattaching/relaying logic.

The `FilterDefault` values of the messages filters are currently
hardcoded.

The values of the message filters are not currently user-settable.

This introduces a new user event, eventChannelDetach, which stores an
upstreamConn (which might become invalid at the time of processing), and
a channel name, used for auto-detaching. Every time the channel detach
timer is refreshed (by receveing a message, etc.), a new timer is
created on the upstreamChannel, which will dispatch this event after the
duration (and discards the previous timer, if any).
2020-12-14 20:54:02 +01:00
Simon Ser e797d90c59
Implement delivery receipts via PING messages
This patch implements basic message delivery receipts via PING and PONG.

When a PRIVMSG or NOTICE message is sent, a PING message with a token is
also sent. The history cursor isn't immediately advanced, instead the
bouncer will wait for a PONG message before doing so.

Self-messages trigger a PING for simplicity's sake. We can't immediately
advance the history cursor in this case, because a prior message might
still have an outstanding PING.

Future work may include optimizations such as removing the need to send
a PING after a self-message, or groupping multiple PING messages
together.

Closes: https://todo.sr.ht/~emersion/soju/11
2020-11-24 14:13:24 +01:00
Simon Ser 05aafb5edf
Add message store abstraction
Introduce a messageStore type, which will allow for multiple
implementations (e.g. in the DB or in-memory instead of on-disk).

The message store is per-user so that we don't need to deal with locking
and it's easier to implement per-user limits.
2020-10-25 17:47:38 +01:00
delthas 28cf1147e8 Add support for the extended-join capability
This simple implementation only advertises extended-join to downstreams
when all upstreams support it.

In the future, it could be modified so that soju buffers incoming
upstream JOINs, sends a WHO, waits for the reply, and sends an extended
join to the downstream; so that soju could advertise that capability
even when some or all upstreams do not support it. This is not the case
in this commit.
2020-09-11 00:10:58 +02:00
Simon Ser 046175f564
Don't update history when msgID is empty in appendLog
Log files don't record all message types. If the message isn't inserted
in the log file, don't update the history cursors for downstream
connections.
2020-08-28 13:35:55 +02:00
Simon Ser 92fece5cd4
Nuke in-memory ring buffer
Instead, always read chat history from logs. Unify the implicit chat
history (pushing history to clients) and explicit chat history
(via the CHATHISTORY command).

Instead of keeping track of ring buffer cursors for each client, use
message IDs.

If necessary, the ring buffer could be re-introduced behind a
common MessageStore interface (could be useful when on-disk logs are
disabled).

References: https://todo.sr.ht/~emersion/soju/80
2020-08-20 20:05:01 +02:00
Simon Ser 8f29ae41a2
Introduce internal message IDs
For now, these can be used as cursors in the logs. Future patches will
introduce functions that perform log queries with message IDs.

The IDs are state-less tokens containing all the required information to
refer to an on-disk log line: network name, entity name, date and byte
offset. The byte offset doesn't need to point to the first byte of the
line, any byte will do (note, this makes it so message IDs aren't
necessarily unique, we may want to change that in the future).

These internal message IDs are not exposed to clients because we don't
support upstream message IDs yet.
2020-08-20 20:05:01 +02:00
Simon Ser 4dae0da59f
Replace networkHistory.offlineClients with clients
Keep the ring buffer alive even if all clients are connected. Keep the
ID of the latest delivered message even for online clients.

As-is, this is a net downgrade: memory usage increases because ring
buffers aren't free'd anymore. However upcoming commits will replace the
ring buffer with log files. This change makes reading from log files
easier.
2020-08-20 17:38:57 +02:00
Hubert Hirtz 81c7e80e0f
Forward RPL_TOPICWHOTIME to downstreams 2020-08-20 11:12:54 +02:00
Hubert Hirtz d957493348
Fix marshalling of channel name in RPL_CREATIONTIME 2020-08-20 09:15:47 +02:00
Simon Ser e523deb15c
go fmt 2020-08-20 09:13:56 +02:00
Simon Ser 385825d010
Improve registration error messages
- Don't print the raw IRC message, since we already show the original
  error message
- Avoid double-printing "registration failed"
2020-08-19 23:35:12 +02:00
Simon Ser bdb132ad98
Implement rate limiting for upstream messages
Allow up to 10 outgoing messages in a burst, then throttle to 1 message
each 2 seconds.

Closes: https://todo.sr.ht/~emersion/soju/87
2020-08-19 19:42:33 +02:00
Simon Ser ee32329a14
Strip message tags in error message
The time tag was causing the registration error messages to be
continuously sent to downstream connections.
2020-08-19 11:50:19 +02:00
Simon Ser 0831dbe6f1
Handle upstream ERROR messages 2020-08-13 15:31:07 +02:00
Simon Ser 9fd69c745e
Handle ERR_NOPERMFORHOST and ERR_YOUREBANNEDCREEP 2020-08-13 15:31:03 +02:00
Simon Ser 7c31c26d86
Don't perform TLS handshake in connectToUpstream
This defers TLS handshake until the first read or write operation. This
allows the upcoming identd server to register the connection before the
TLS handshake is complete, and is necessary because some IRC servers
send an ident request before that.
2020-08-11 10:24:54 +02:00