Persist realname for always-on clients

This commit is contained in:
Conrad Lukawski 2020-07-06 04:08:04 -04:00
parent 7d596add87
commit 6f8711da3b
5 changed files with 51 additions and 10 deletions

View File

@ -39,7 +39,8 @@ const (
keyAccountChannels = "account.channels %s" // channels registered to the account
keyAccountJoinedChannels = "account.joinedto %s" // channels a persistent client has joined
keyAccountLastSeen = "account.lastseen %s"
keyAccountModes = "account.modes %s" // user modes for the always-on client as a string
keyAccountModes = "account.modes %s" // user modes for the always-on client as a string
keyAccountRealname = "account.realname %s" // client realname stored as string
keyVHostQueueAcctToId = "vhostQueue %s"
vhostRequestIdx = "vhostQueue"
@ -127,7 +128,13 @@ func (am *AccountManager) createAlwaysOnClients(config *Config) {
account, err := am.LoadAccount(accountName)
if err == nil && account.Verified &&
persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, account.Settings.AlwaysOn) {
am.server.AddAlwaysOnClient(account, am.loadChannels(accountName), am.loadLastSeen(accountName), am.loadModes(accountName))
am.server.AddAlwaysOnClient(
account,
am.loadChannels(accountName),
am.loadLastSeen(accountName),
am.loadModes(accountName),
am.loadRealname(accountName),
)
}
}
}
@ -650,6 +657,30 @@ func (am *AccountManager) loadLastSeen(account string) (lastSeen map[string]time
return
}
func (am *AccountManager) saveRealname(account string, realname string) {
key := fmt.Sprintf(keyAccountRealname, account)
am.server.store.Update(func(tx *buntdb.Tx) error {
if realname != "" {
tx.Set(key, realname, nil)
} else {
tx.Delete(key)
}
return nil
})
}
func (am *AccountManager) loadRealname(account string) (realname string) {
key := fmt.Sprintf(keyAccountRealname, account)
am.server.store.Update(func(tx *buntdb.Tx) error {
realname, _ = tx.Get(key)
return nil
})
if realname == "" {
return ""
}
return
}
func (am *AccountManager) addRemoveCertfp(account, certfp string, add bool, hasPrivs bool) (err error) {
certfp, err = utils.NormalizeCertfp(certfp)
if err != nil {
@ -874,6 +905,9 @@ func (am *AccountManager) Verify(client *Client, account string, code string) er
am.server.RandomlyRename(currentClient)
}
}
if client.AlwaysOn() {
client.markDirty(IncludeRealname)
}
return nil
}

View File

@ -365,7 +365,7 @@ func (server *Server) RunClient(conn IRCConn) {
client.run(session)
}
func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string, lastSeen map[string]time.Time, uModes modes.Modes) {
func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string, lastSeen map[string]time.Time, uModes modes.Modes, realname string) {
now := time.Now().UTC()
config := server.Config()
if lastSeen == nil && account.Settings.AutoreplayMissed {
@ -386,6 +386,7 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string,
realIP: utils.IPv4LoopbackAddress,
alwaysOn: true,
realname: realname,
}
client.SetMode(modes.TLS, true)
@ -1707,6 +1708,7 @@ const (
IncludeChannels uint = 1 << iota
IncludeLastSeen
IncludeUserModes
IncludeRealname
)
func (client *Client) markDirty(dirtyBits uint) {
@ -1778,6 +1780,9 @@ func (client *Client) performWrite(additionalDirtyBits uint) {
}
client.server.accounts.saveModes(account, uModes)
}
if (dirtyBits & IncludeRealname) != 0 {
client.server.accounts.saveRealname(account, client.realname)
}
}
// Blocking store; see Channel.Store and Socket.BlockingWrite

View File

@ -122,7 +122,6 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick
accountName := client.accountName
settings := client.accountSettings
registered := client.registered
realname := client.realname
client.stateMutex.RUnlock()
// recompute always-on status, because client.alwaysOn is not set for unregistered clients
@ -225,12 +224,6 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick
client.server.stats.AddRegistered(invisible, operator)
}
session.autoreplayMissedSince = lastSeen
// XXX SetNames only changes names if they are unset, so the realname change only
// takes effect on first attach to an always-on client (good), but the user/ident
// change is always a no-op (bad). we could make user/ident act the same way as
// realname, but then we'd have to send CHGHOST and i don't want to deal with that
// for performance reasons
currentClient.SetNames("user", realname, true)
// successful reattach!
return newNick, nil, back
} else if currentClient == client && currentClient.Nick() == newNick {

View File

@ -373,7 +373,11 @@ func (client *Client) SetMode(mode modes.Mode, on bool) bool {
func (client *Client) SetRealname(realname string) {
client.stateMutex.Lock()
client.realname = realname
alwaysOn := client.alwaysOn
client.stateMutex.Unlock()
if alwaysOn {
client.markDirty(IncludeRealname)
}
}
func (client *Client) Channels() (result []*Channel) {

View File

@ -2514,6 +2514,11 @@ func sceneHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
// SETNAME <realname>
func setnameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
realname := msg.Params[0]
if realname == "" {
rb.Add(nil, server.name, "FAIL", "SETNAME", "INVALID_REALNAME", client.t("Realname is not valid"))
return false
}
client.SetRealname(realname)
details := client.Details()