mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
implement #199
This commit is contained in:
parent
0ea210c28c
commit
be86684e96
@ -65,6 +65,7 @@ type Client struct {
|
|||||||
nickMaskString string // cache for nickmask string since it's used with lots of replies
|
nickMaskString string // cache for nickmask string since it's used with lots of replies
|
||||||
nickTimer *NickTimer
|
nickTimer *NickTimer
|
||||||
operName string
|
operName string
|
||||||
|
preregNick string
|
||||||
proxiedIP net.IP // actual remote IP if using the PROXY protocol
|
proxiedIP net.IP // actual remote IP if using the PROXY protocol
|
||||||
quitMessage string
|
quitMessage string
|
||||||
rawHostname string
|
rawHostname string
|
||||||
|
@ -61,6 +61,7 @@ func (conf *PassConfig) PasswordBytes() []byte {
|
|||||||
type AccountConfig struct {
|
type AccountConfig struct {
|
||||||
Registration AccountRegistrationConfig
|
Registration AccountRegistrationConfig
|
||||||
AuthenticationEnabled bool `yaml:"authentication-enabled"`
|
AuthenticationEnabled bool `yaml:"authentication-enabled"`
|
||||||
|
SkipServerPassword bool `yaml:"skip-server-password"`
|
||||||
NickReservation NickReservationConfig `yaml:"nick-reservation"`
|
NickReservation NickReservationConfig `yaml:"nick-reservation"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +142,30 @@ func (client *Client) SetAccountName(account string) (changed bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) Authorized() bool {
|
||||||
|
client.stateMutex.RLock()
|
||||||
|
defer client.stateMutex.RUnlock()
|
||||||
|
return client.authorized
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) SetAuthorized(authorized bool) {
|
||||||
|
client.stateMutex.Lock()
|
||||||
|
defer client.stateMutex.Unlock()
|
||||||
|
client.authorized = authorized
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) PreregNick() string {
|
||||||
|
client.stateMutex.RLock()
|
||||||
|
defer client.stateMutex.RUnlock()
|
||||||
|
return client.preregNick
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) SetPreregNick(preregNick string) {
|
||||||
|
client.stateMutex.Lock()
|
||||||
|
defer client.stateMutex.Unlock()
|
||||||
|
client.preregNick = preregNick
|
||||||
|
}
|
||||||
|
|
||||||
func (client *Client) HasMode(mode modes.Mode) bool {
|
func (client *Client) HasMode(mode modes.Mode) bool {
|
||||||
client.stateMutex.RLock()
|
client.stateMutex.RLock()
|
||||||
defer client.stateMutex.RUnlock()
|
defer client.stateMutex.RUnlock()
|
||||||
|
@ -319,6 +319,10 @@ func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage,
|
|||||||
// let the SASL handler do its thing
|
// let the SASL handler do its thing
|
||||||
exiting := handler(server, client, client.saslMechanism, data, rb)
|
exiting := handler(server, client, client.saslMechanism, data, rb)
|
||||||
|
|
||||||
|
if client.LoggedIntoAccount() && server.AccountConfig().SkipServerPassword {
|
||||||
|
client.SetAuthorized(true)
|
||||||
|
}
|
||||||
|
|
||||||
// wait 'til SASL is done before emptying the sasl vars
|
// wait 'til SASL is done before emptying the sasl vars
|
||||||
client.saslInProgress = false
|
client.saslInProgress = false
|
||||||
client.saslMechanism = ""
|
client.saslMechanism = ""
|
||||||
@ -491,9 +495,8 @@ func capHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
|||||||
rb.Add(nil, server.name, "CAP", client.nick, "ACK", capString)
|
rb.Add(nil, server.name, "CAP", client.nick, "ACK", capString)
|
||||||
|
|
||||||
case "END":
|
case "END":
|
||||||
if !client.registered {
|
if !client.Registered() {
|
||||||
client.capState = caps.NegotiatedState
|
client.capState = caps.NegotiatedState
|
||||||
server.tryRegister(client)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1633,12 +1636,12 @@ func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
|
|||||||
|
|
||||||
// NICK <nickname>
|
// NICK <nickname>
|
||||||
func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
if !client.authorized {
|
if client.Registered() {
|
||||||
client.Quit("Bad password")
|
performNickChange(server, client, client, msg.Params[0], rb)
|
||||||
return true
|
} else {
|
||||||
|
client.SetPreregNick(msg.Params[0])
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
return performNickChange(server, client, client, msg.Params[0], rb)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTICE <target>{,<target>} <message>
|
// NOTICE <target>{,<target>} <message>
|
||||||
@ -1831,14 +1834,14 @@ func partHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
|
|
||||||
// PASS <password>
|
// PASS <password>
|
||||||
func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
if client.registered {
|
if client.Registered() {
|
||||||
rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
|
rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no password exists, skip checking
|
// if no password exists, skip checking
|
||||||
if len(server.password) == 0 {
|
if len(server.password) == 0 {
|
||||||
client.authorized = true
|
client.SetAuthorized(true)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1850,7 +1853,7 @@ func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
client.authorized = true
|
client.SetAuthorized(true)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1942,7 +1945,7 @@ func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
|||||||
// http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
// http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
||||||
func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
// only allow unregistered clients to use this command
|
// only allow unregistered clients to use this command
|
||||||
if client.registered || client.proxiedIP != nil {
|
if client.Registered() || client.proxiedIP != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2106,7 +2109,8 @@ func sanickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
|||||||
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], client.t("No such nick"))
|
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], client.t("No such nick"))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return performNickChange(server, client, target, msg.Params[1], rb)
|
performNickChange(server, client, target, msg.Params[1], rb)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCENE <target> <message>
|
// SCENE <target> <message>
|
||||||
@ -2320,16 +2324,11 @@ func unKLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
|||||||
|
|
||||||
// USER <username> * 0 <realname>
|
// USER <username> * 0 <realname>
|
||||||
func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
if client.registered {
|
if client.Registered() {
|
||||||
rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
|
rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !client.authorized {
|
|
||||||
client.Quit("Bad password")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if client.username != "" && client.realname != "" {
|
if client.username != "" && client.realname != "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -2350,8 +2349,6 @@ func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
client.realname = msg.Params[3]
|
client.realname = msg.Params[3]
|
||||||
}
|
}
|
||||||
|
|
||||||
server.tryRegister(client)
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2403,7 +2400,7 @@ func versionHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
|||||||
// WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
|
// WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
|
||||||
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
// only allow unregistered clients to use this command
|
// only allow unregistered clients to use this command
|
||||||
if client.registered || client.proxiedIP != nil {
|
if client.Registered() || client.proxiedIP != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// returns whether the change succeeded or failed
|
||||||
func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
|
func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
|
||||||
nickname := strings.TrimSpace(newnick)
|
nickname := strings.TrimSpace(newnick)
|
||||||
cfnick, err := CasefoldName(nickname)
|
cfnick, err := CasefoldName(nickname)
|
||||||
@ -38,7 +39,7 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if target.Nick() == nickname {
|
if target.Nick() == nickname {
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
hadNick := target.HasNick()
|
hadNick := target.HasNick()
|
||||||
@ -49,7 +50,7 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
|
|||||||
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
|
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
|
||||||
return false
|
return false
|
||||||
} else if err == errNicknameReserved {
|
} else if err == errNicknameReserved {
|
||||||
client.Send(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is reserved by a different account"))
|
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is reserved by a different account"))
|
||||||
return false
|
return false
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
|
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
|
||||||
@ -67,12 +68,11 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.registered {
|
if target.Registered() {
|
||||||
client.server.monitorManager.AlertAbout(target, true)
|
client.server.monitorManager.AlertAbout(target, true)
|
||||||
} else {
|
|
||||||
server.tryRegister(target)
|
|
||||||
}
|
}
|
||||||
return false
|
// else: Run() will attempt registration immediately after this
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) RandomlyRename(client *Client) {
|
func (server *Server) RandomlyRename(client *Client) {
|
||||||
|
@ -416,8 +416,27 @@ func (server *Server) generateMessageID() string {
|
|||||||
//
|
//
|
||||||
|
|
||||||
func (server *Server) tryRegister(c *Client) {
|
func (server *Server) tryRegister(c *Client) {
|
||||||
if c.registered || !c.HasNick() || !c.HasUsername() ||
|
if c.Registered() {
|
||||||
(c.capState == caps.NegotiatingState) {
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
preregNick := c.PreregNick()
|
||||||
|
if preregNick == "" || !c.HasUsername() || c.capState == caps.NegotiatingState {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// client MUST send PASS (or AUTHENTICATE, if skip-server-password is set)
|
||||||
|
// before completing the other registration commands
|
||||||
|
if !c.Authorized() {
|
||||||
|
c.Quit(c.t("Bad password"))
|
||||||
|
c.destroy(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rb := NewResponseBuffer(c)
|
||||||
|
nickAssigned := performNickChange(server, c, c, preregNick, rb)
|
||||||
|
rb.Send()
|
||||||
|
if !nickAssigned {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,7 +466,7 @@ func (server *Server) tryRegister(c *Client) {
|
|||||||
//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
|
//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
|
||||||
c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
|
c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
|
||||||
|
|
||||||
rb := NewResponseBuffer(c)
|
rb = NewResponseBuffer(c)
|
||||||
c.RplISupport(rb)
|
c.RplISupport(rb)
|
||||||
server.MOTD(c, rb)
|
server.MOTD(c, rb)
|
||||||
rb.Send()
|
rb.Send()
|
||||||
|
@ -170,6 +170,13 @@ accounts:
|
|||||||
# is account authentication enabled?
|
# is account authentication enabled?
|
||||||
authentication-enabled: true
|
authentication-enabled: true
|
||||||
|
|
||||||
|
# some clients (notably Pidgin and Hexchat) offer only a single password field,
|
||||||
|
# which makes it impossible to specify a separate server password (for the PASS
|
||||||
|
# command) and SASL password. if this option is set to true, a client that
|
||||||
|
# successfully authenticates with SASL will not be required to send
|
||||||
|
# PASS as well, so it can be configured to authenticate with SASL only.
|
||||||
|
skip-server-password: false
|
||||||
|
|
||||||
# nick-reservation controls how, and whether, nicknames are linked to accounts
|
# nick-reservation controls how, and whether, nicknames are linked to accounts
|
||||||
nick-reservation:
|
nick-reservation:
|
||||||
# is there any enforcement of reserved nicknames?
|
# is there any enforcement of reserved nicknames?
|
||||||
|
Loading…
Reference in New Issue
Block a user