Compare commits
1
Commits
main
..
2a2bd820ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a2bd820ec |
@@ -264,25 +264,6 @@ func (database *Database) GetSessionByNick(
|
|||||||
return sessionID, nil
|
return sessionID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSessionNick returns the nick a session holds.
|
|
||||||
func (database *Database) GetSessionNick(
|
|
||||||
ctx context.Context,
|
|
||||||
sessionID int64,
|
|
||||||
) (string, error) {
|
|
||||||
var nick string
|
|
||||||
|
|
||||||
err := database.conn.QueryRowContext(
|
|
||||||
ctx,
|
|
||||||
"SELECT nick FROM sessions WHERE id = ?",
|
|
||||||
sessionID,
|
|
||||||
).Scan(&nick)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("get session nick: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nick, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SessionHostInfo holds the username, hostname, and IP
|
// SessionHostInfo holds the username, hostname, and IP
|
||||||
// for a session.
|
// for a session.
|
||||||
type SessionHostInfo struct {
|
type SessionHostInfo struct {
|
||||||
|
|||||||
@@ -92,10 +92,9 @@ func (c *Conn) handleNick(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take the nick the session holds, not newNick: another
|
c.mu.Lock()
|
||||||
// client of the session may have changed it again since
|
c.nick = newNick
|
||||||
// ChangeNick stored newNick.
|
c.mu.Unlock()
|
||||||
c.loadSessionNick(ctx)
|
|
||||||
|
|
||||||
// Echo NICK change to the client on wire.
|
// Echo NICK change to the client on wire.
|
||||||
c.send(FormatMessage(oldMask, "NICK", newNick))
|
c.send(FormatMessage(oldMask, "NICK", newNick))
|
||||||
|
|||||||
@@ -313,22 +313,6 @@ func (c *Conn) currentNick() string {
|
|||||||
return c.nick
|
return c.nick
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadSessionNick sets c.nick to the nick the connection's
|
|
||||||
// session holds in the database, read by session ID. The
|
|
||||||
// connection's own NICK and the relay passing on a NICK line
|
|
||||||
// both call it, and it reads and sets the nick under c.mu, so
|
|
||||||
// whichever runs last leaves the connection on its session's
|
|
||||||
// nick. If the read fails, c.nick is left as it is.
|
|
||||||
func (c *Conn) loadSessionNick(ctx context.Context) {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
|
|
||||||
nick, err := c.database.GetSessionNick(ctx, c.sessionID)
|
|
||||||
if err == nil {
|
|
||||||
c.nick = nick
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// send writes a formatted IRC line to the connection.
|
// send writes a formatted IRC line to the connection.
|
||||||
func (c *Conn) send(line string) {
|
func (c *Conn) send(line string) {
|
||||||
c.sendWithin(writeTimeout, line)
|
c.sendWithin(writeTimeout, line)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func (c *Conn) drainQueue(ctx context.Context) bool {
|
|||||||
//
|
//
|
||||||
//nolint:cyclop // dispatch table
|
//nolint:cyclop // dispatch table
|
||||||
func (c *Conn) deliverIRCMessage(
|
func (c *Conn) deliverIRCMessage(
|
||||||
ctx context.Context,
|
_ context.Context,
|
||||||
msg *db.IRCMessage,
|
msg *db.IRCMessage,
|
||||||
) {
|
) {
|
||||||
command := msg.Command
|
command := msg.Command
|
||||||
@@ -120,7 +120,7 @@ func (c *Conn) deliverIRCMessage(
|
|||||||
case command == irc.CmdPart:
|
case command == irc.CmdPart:
|
||||||
c.deliverPart(msg, text)
|
c.deliverPart(msg, text)
|
||||||
case command == irc.CmdNick:
|
case command == irc.CmdNick:
|
||||||
c.deliverNickChange(ctx, msg, text)
|
c.deliverNickChange(msg, text)
|
||||||
case command == irc.CmdQuit:
|
case command == irc.CmdQuit:
|
||||||
c.deliverQuitMsg(msg, text)
|
c.deliverQuitMsg(msg, text)
|
||||||
case command == irc.CmdTopic:
|
case command == irc.CmdTopic:
|
||||||
@@ -230,17 +230,21 @@ func (c *Conn) deliverPart(msg *db.IRCMessage, text string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deliverNickChange sends a NICK change notification. The
|
// deliverNickChange sends a NICK change notification. When
|
||||||
// change may be its own session's, made from another client,
|
// the old nick is the connection's own, the change was made
|
||||||
// so the connection first takes the nick its session holds
|
// from another client of its session, as nicks are unique,
|
||||||
// now. It does not go by the line's old nick: the connection
|
// and the connection takes the new nick too.
|
||||||
// may have taken that nick after another user gave it up.
|
|
||||||
func (c *Conn) deliverNickChange(
|
func (c *Conn) deliverNickChange(
|
||||||
ctx context.Context,
|
|
||||||
msg *db.IRCMessage,
|
msg *db.IRCMessage,
|
||||||
newNick string,
|
newNick string,
|
||||||
) {
|
) {
|
||||||
c.loadSessionNick(ctx)
|
c.mu.Lock()
|
||||||
|
|
||||||
|
if msg.From == c.nick {
|
||||||
|
c.nick = newNick
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
prefix := msg.From + "!" + msg.From + "@*"
|
prefix := msg.From + "!" + msg.From + "@*"
|
||||||
|
|
||||||
|
|||||||
@@ -655,43 +655,3 @@ func TestRelayNickChangeFromHTTPAPI(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRelayNickChangeKeepsTakenNick checks that an IRC
|
|
||||||
// listener connection which takes a nick another user has
|
|
||||||
// given up keeps it when that user's change reaches it
|
|
||||||
// afterwards: what it then sends goes out under the nick its
|
|
||||||
// session holds.
|
|
||||||
func TestRelayNickChangeKeepsTakenNick(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
env := newTestEnv(t)
|
|
||||||
|
|
||||||
bob := env.dial(t)
|
|
||||||
bob.register("bob")
|
|
||||||
bob.sendAndExpect("NICK bob2", " NICK bob2")
|
|
||||||
|
|
||||||
alice := env.dial(t)
|
|
||||||
alice.register("alice")
|
|
||||||
alice.sendAndExpect("NICK bob", " NICK bob")
|
|
||||||
alice.joinAndDrain("#chan")
|
|
||||||
|
|
||||||
bob.joinAndDrain("#chan")
|
|
||||||
|
|
||||||
// Bob's change reaches alice only now, as it does when she
|
|
||||||
// takes his old nick before her connection has passed the
|
|
||||||
// change on. She holds bob now, so it is queued to bob.
|
|
||||||
env.queueMessage(t, "bob", "NICK", "bob", "", []string{"bob2"})
|
|
||||||
|
|
||||||
alice.readUntil(func(l string) bool {
|
|
||||||
return l == ":bob!bob@* NICK bob2"
|
|
||||||
})
|
|
||||||
|
|
||||||
alice.send("PRIVMSG #chan :hi there")
|
|
||||||
|
|
||||||
const want = ":bob!bob@* PRIVMSG #chan :hi there"
|
|
||||||
|
|
||||||
got := bob.readLine()
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("got %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user