mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-01 16:39:26 +01:00
Merge pull request #341 from oragono/restrict-usernames
Restrict idents as other servers do
This commit is contained in:
commit
057d00b2c8
@ -176,12 +176,15 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) {
|
|||||||
client.Notice(client.t("*** Looking up your username"))
|
client.Notice(client.t("*** Looking up your username"))
|
||||||
resp, err := ident.Query(clientHost, serverPort, clientPort, IdentTimeoutSeconds)
|
resp, err := ident.Query(clientHost, serverPort, clientPort, IdentTimeoutSeconds)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
username := resp.Identifier
|
ident := resp.Identifier
|
||||||
cfusername, err := CasefoldName(username)
|
if config.Limits.IdentLen < len(ident) {
|
||||||
if err == nil {
|
ident = ident[:config.Limits.IdentLen]
|
||||||
|
}
|
||||||
|
if isIdent(ident) {
|
||||||
|
identLower := strings.ToLower(ident) // idents can only be ASCII chars only
|
||||||
client.Notice(client.t("*** Found your username"))
|
client.Notice(client.t("*** Found your username"))
|
||||||
client.username = username
|
client.username = ident
|
||||||
client.usernameCasefolded = cfusername
|
client.usernameCasefolded = identLower
|
||||||
// we don't need to updateNickMask here since nickMask is not used for anything yet
|
// we don't need to updateNickMask here since nickMask is not used for anything yet
|
||||||
} else {
|
} else {
|
||||||
client.Notice(client.t("*** Got a malformed username, ignoring"))
|
client.Notice(client.t("*** Got a malformed username, ignoring"))
|
||||||
@ -623,12 +626,15 @@ func (client *Client) HasUsername() bool {
|
|||||||
return client.username != "" && client.username != "*"
|
return client.username != "" && client.username != "*"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetNames sets the client's ident and realname.
|
||||||
func (client *Client) SetNames(username, realname string) error {
|
func (client *Client) SetNames(username, realname string) error {
|
||||||
usernameCasefolded, err := CasefoldName(username)
|
// do this before casefolding to ensure these are actually ascii
|
||||||
if err != nil {
|
if !isIdent(username) {
|
||||||
return errInvalidUsername
|
return errInvalidUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usernameCasefolded := strings.ToLower(username) // only ascii is supported in idents anyway
|
||||||
|
|
||||||
client.stateMutex.Lock()
|
client.stateMutex.Lock()
|
||||||
defer client.stateMutex.Unlock()
|
defer client.stateMutex.Unlock()
|
||||||
|
|
||||||
|
@ -206,12 +206,13 @@ type Limits struct {
|
|||||||
AwayLen int `yaml:"awaylen"`
|
AwayLen int `yaml:"awaylen"`
|
||||||
ChanListModes int `yaml:"chan-list-modes"`
|
ChanListModes int `yaml:"chan-list-modes"`
|
||||||
ChannelLen int `yaml:"channellen"`
|
ChannelLen int `yaml:"channellen"`
|
||||||
|
IdentLen int `yaml:"identlen"`
|
||||||
KickLen int `yaml:"kicklen"`
|
KickLen int `yaml:"kicklen"`
|
||||||
|
LineLen LineLenLimits `yaml:"linelen"`
|
||||||
MonitorEntries int `yaml:"monitor-entries"`
|
MonitorEntries int `yaml:"monitor-entries"`
|
||||||
NickLen int `yaml:"nicklen"`
|
NickLen int `yaml:"nicklen"`
|
||||||
TopicLen int `yaml:"topiclen"`
|
TopicLen int `yaml:"topiclen"`
|
||||||
WhowasEntries int `yaml:"whowas-entries"`
|
WhowasEntries int `yaml:"whowas-entries"`
|
||||||
LineLen LineLenLimits `yaml:"linelen"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// STSConfig controls the STS configuration/
|
// STSConfig controls the STS configuration/
|
||||||
@ -491,6 +492,10 @@ func LoadConfig(filename string) (config *Config, err error) {
|
|||||||
if len(config.Server.Listen) == 0 {
|
if len(config.Server.Listen) == 0 {
|
||||||
return nil, ErrNoListenersDefined
|
return nil, ErrNoListenersDefined
|
||||||
}
|
}
|
||||||
|
//dan: automagically fix identlen until a few releases in the future (from now, 0.12.0), being a newly-introduced limit
|
||||||
|
if config.Limits.IdentLen < 1 {
|
||||||
|
config.Limits.IdentLen = 20
|
||||||
|
}
|
||||||
if config.Limits.NickLen < 1 || config.Limits.ChannelLen < 2 || config.Limits.AwayLen < 1 || config.Limits.KickLen < 1 || config.Limits.TopicLen < 1 {
|
if config.Limits.NickLen < 1 || config.Limits.ChannelLen < 2 || config.Limits.AwayLen < 1 || config.Limits.KickLen < 1 || config.Limits.TopicLen < 1 {
|
||||||
return nil, ErrLimitsAreInsane
|
return nil, ErrLimitsAreInsane
|
||||||
}
|
}
|
||||||
|
@ -2193,10 +2193,15 @@ func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
err := client.SetNames(msg.Params[0], msg.Params[3])
|
ident := msg.Params[0]
|
||||||
|
identLen := server.Limits().IdentLen
|
||||||
|
if identLen-1 < len(ident) {
|
||||||
|
ident = ident[:server.Limits().IdentLen-1] // -1 as SetNames adds the ~ at the start for us
|
||||||
|
}
|
||||||
|
|
||||||
|
err := client.SetNames(ident, msg.Params[3])
|
||||||
if err == errInvalidUsername {
|
if err == errInvalidUsername {
|
||||||
rb.Add(nil, "", "ERROR", client.t("Malformed username"))
|
rb.Add(nil, server.name, ERR_INVALIDUSERNAME, client.t("Malformed username"))
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -143,6 +143,7 @@ const (
|
|||||||
ERR_YOUREBANNEDCREEP = "465"
|
ERR_YOUREBANNEDCREEP = "465"
|
||||||
ERR_YOUWILLBEBANNED = "466"
|
ERR_YOUWILLBEBANNED = "466"
|
||||||
ERR_KEYSET = "467"
|
ERR_KEYSET = "467"
|
||||||
|
ERR_INVALIDUSERNAME = "468"
|
||||||
ERR_CHANNELISFULL = "471"
|
ERR_CHANNELISFULL = "471"
|
||||||
ERR_UNKNOWNMODE = "472"
|
ERR_UNKNOWNMODE = "472"
|
||||||
ERR_INVITEONLYCHAN = "473"
|
ERR_INVITEONLYCHAN = "473"
|
||||||
|
@ -128,6 +128,32 @@ func isBoring(name string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns true if the given name is a valid ident, using a mix of Insp and
|
||||||
|
// Chary's ident restrictions.
|
||||||
|
func isIdent(name string) bool {
|
||||||
|
if len(name) < 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(name); i++ {
|
||||||
|
chr := name[i]
|
||||||
|
if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') {
|
||||||
|
continue // alphanumerics
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
return false // first char must be alnum
|
||||||
|
}
|
||||||
|
switch chr {
|
||||||
|
case '[', '\\', ']', '^', '_', '{', '|', '}', '-', '.', '`':
|
||||||
|
continue // allowed chars
|
||||||
|
default:
|
||||||
|
return false // disallowed chars
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Skeleton produces a canonicalized identifier that tries to catch
|
// Skeleton produces a canonicalized identifier that tries to catch
|
||||||
// homoglyphic / confusable identifiers. It's a tweaked version of the TR39
|
// homoglyphic / confusable identifiers. It's a tweaked version of the TR39
|
||||||
// skeleton algorithm. We apply the skeleton algorithm first and only then casefold,
|
// skeleton algorithm. We apply the skeleton algorithm first and only then casefold,
|
||||||
|
@ -140,6 +140,22 @@ func TestIsBoring(t *testing.T) {
|
|||||||
assertBoring("Νικηφόρος", false)
|
assertBoring("Νικηφόρος", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsIdent(t *testing.T) {
|
||||||
|
assertIdent := func(str string, expected bool) {
|
||||||
|
if isIdent(str) != expected {
|
||||||
|
t.Errorf("expected [%s] to have identness [%t], but got [%t]", str, expected, !expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertIdent("warning", true)
|
||||||
|
assertIdent("sid3225", true)
|
||||||
|
assertIdent("dan.oak25", true)
|
||||||
|
assertIdent("dan.oak[25]", true)
|
||||||
|
assertIdent("phi@#$%ip", false)
|
||||||
|
assertIdent("Νικηφόρος", false)
|
||||||
|
assertIdent("-dan56", false)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSkeleton(t *testing.T) {
|
func TestSkeleton(t *testing.T) {
|
||||||
skeleton := func(str string) string {
|
skeleton := func(str string) string {
|
||||||
skel, err := Skeleton(str)
|
skel, err := Skeleton(str)
|
||||||
|
@ -415,6 +415,9 @@ limits:
|
|||||||
# nicklen is the max nick length allowed
|
# nicklen is the max nick length allowed
|
||||||
nicklen: 32
|
nicklen: 32
|
||||||
|
|
||||||
|
# identlen is the max ident length allowed
|
||||||
|
identlen: 20
|
||||||
|
|
||||||
# channellen is the max channel length allowed
|
# channellen is the max channel length allowed
|
||||||
channellen: 64
|
channellen: 64
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user