diff --git a/irc/channel.go b/irc/channel.go index 8693e037..b9af37fe 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -30,6 +30,7 @@ type Channel struct { key string members MemberSet membersCache []*Client // allow iteration over channel members without holding the lock + memberJoinTimes map[*Client]time.Time name string nameCasefolded string server *Server @@ -57,11 +58,12 @@ func NewChannel(s *Server, name, casefoldedName string, registered bool) *Channe config := s.Config() channel := &Channel{ - createdTime: time.Now().UTC(), // may be overwritten by applyRegInfo - members: make(MemberSet), - name: name, - nameCasefolded: casefoldedName, - server: s, + createdTime: time.Now().UTC(), // may be overwritten by applyRegInfo + members: make(MemberSet), + memberJoinTimes: make(map[*Client]time.Time), + name: name, + nameCasefolded: casefoldedName, + server: s, } channel.initializeLists() @@ -550,6 +552,16 @@ func (channel *Channel) ClientModeStrings(client *Client) []string { } } +func (channel *Channel) ClientJoinTime(client *Client) *time.Time { + channel.stateMutex.RLock() + defer channel.stateMutex.RUnlock() + time, present := channel.memberJoinTimes[client] + if present { + return &time + } + return nil +} + func (channel *Channel) ClientHasPrivsOver(client *Client, target *Client) bool { channel.stateMutex.RLock() founder := channel.registeredFounder @@ -726,6 +738,7 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp defer channel.stateMutex.Unlock() channel.members.Add(client) + channel.memberJoinTimes[client] = time.Now() firstJoin := len(channel.members) == 1 newChannel := firstJoin && channel.registeredFounder == "" if newChannel { @@ -1364,6 +1377,7 @@ func (channel *Channel) Quit(client *Client) { channel.stateMutex.Lock() channel.members.Remove(client) + delete(channel.memberJoinTimes, client) channelEmpty := len(channel.members) == 0 channel.stateMutex.Unlock() channel.regenerateMembersCache() diff --git a/irc/handlers.go b/irc/handlers.go index 880f6d5f..d6deaa35 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -939,7 +939,13 @@ func extjwtHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re claims["joined"] = 0 claims["cmodes"] = []string{} if channel.hasClient(client) { - claims["joined"] = time.Now().Unix() - 100 //TODO(dan): um we need to store when clients joined for reals + joinTime := channel.ClientJoinTime(client) + if joinTime == nil { + // shouldn't happen, only in races + rb.Add(nil, server.name, "FAIL", "EXTJWT", "UNKNOWN_ERROR", client.t("Channel join time is inconsistent, JWT not generated")) + return false + } + claims["joined"] = joinTime.Unix() claims["cmodes"] = channel.ClientModeStrings(client) } }