summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/channel/channel.go29
-rw-r--r--server/user/user.go29
-rw-r--r--server/validate/validate.go41
3 files changed, 85 insertions, 14 deletions
diff --git a/server/channel/channel.go b/server/channel/channel.go
index 9a3134e..69f2400 100644
--- a/server/channel/channel.go
+++ b/server/channel/channel.go
@@ -4,6 +4,7 @@ import (
"citrons.xyz/talk/proto"
"citrons.xyz/talk/server/object"
"citrons.xyz/talk/server/session"
+ "citrons.xyz/talk/server/validate"
"citrons.xyz/talk/server/user"
)
@@ -35,11 +36,16 @@ func NewStore(world *object.World) *ChannelStore {
}
func (cs *ChannelStore) CreateChannel(name string) (*Channel, *proto.Fail) {
- if cs.byName[name] != nil {
+ if cs.ByName(name) != nil {
return nil, &proto.Fail {
"name-taken", "", map[string]string {"": name},
}
}
+ if !validate.Name(name) {
+ return nil, &proto.Fail {
+ "invalid-name", "", map[string]string {"": name},
+ }
+ }
var c Channel
c.store = cs
c.name = name
@@ -47,13 +53,13 @@ func (cs *ChannelStore) CreateChannel(name string) (*Channel, *proto.Fail) {
c.byId = make(map[string]int)
c.defaultMembership = DefaultMembership
- cs.byName[name] = &c
+ cs.byName[validate.Fold(name)] = &c
c.id = cs.world.NewObject(&c)
return &c, nil
}
func (cs *ChannelStore) ByName(name string) *Channel {
- return cs.byName[name]
+ return cs.byName[validate.Fold(name)]
}
func (c *Channel) Name() string {
@@ -65,13 +71,22 @@ func (c *Channel) Id() string {
}
func (c *Channel) Rename(name string) *proto.Fail {
- if c.store.byName[name] != nil {
+ if !validate.Name(name) {
+ return &proto.Fail {
+ "invalid-name", "", map[string]string {"": name},
+ }
+ }
+ if validate.Fold(name) == validate.Fold(c.name) {
+ c.name = name
+ return nil
+ }
+ if c.store.ByName(name) != nil {
return &proto.Fail {
"name-taken", "", map[string]string {"": name},
}
}
- c.store.byName[c.name] = nil
- c.store.byName[name] = c
+ c.store.byName[validate.Fold(c.name)] = nil
+ c.store.byName[validate.Fold(name)] = c
c.name = name
return nil
}
@@ -144,7 +159,7 @@ func (c *Channel) Delete() {
default:
}
}
- delete(c.store.byName, c.name)
+ delete(c.store.byName, validate.Fold(c.name))
c.store.world.RemoveObject(c.id)
deleted := Tombstone {c.name}
diff --git a/server/user/user.go b/server/user/user.go
index 41a5c4f..0f20bf1 100644
--- a/server/user/user.go
+++ b/server/user/user.go
@@ -3,6 +3,7 @@ package user
import (
"citrons.xyz/talk/server/object"
"citrons.xyz/talk/server/session"
+ "citrons.xyz/talk/server/validate"
"citrons.xyz/talk/proto"
)
@@ -32,22 +33,27 @@ func NewStore(world *object.World) *UserStore {
}
func (us *UserStore) CreateUser(name string) (*User, *proto.Fail) {
- if us.byName[name] != nil {
+ if us.ByName(name) != nil {
return nil, &proto.Fail {
"name-taken", "", map[string]string {"": name},
}
}
+ if !validate.Name(name) {
+ return nil, &proto.Fail {
+ "invalid-name", "", map[string]string {"": name},
+ }
+ }
var u User
u.store = us
u.name = name
- us.byName[name] = &u
+ us.byName[validate.Fold(name)] = &u
u.id = us.world.NewObject(&u)
u.Channels = make(map[string]bool)
return &u, nil
}
func (us *UserStore) ByName(name string) *User {
- return us.byName[name]
+ return us.byName[validate.Fold(name)]
}
func (u *User) Name() string {
@@ -59,13 +65,22 @@ func (u *User) Id() string {
}
func (u *User) Rename(name string) *proto.Fail {
- if u.store.byName[name] != nil {
+ if !validate.Name(name) {
+ return &proto.Fail {
+ "invalid-name", "", map[string]string {"": name},
+ }
+ }
+ if validate.Fold(name) == validate.Fold(u.name) {
+ u.name = name
+ return nil
+ }
+ if u.store.ByName(name) != nil {
return &proto.Fail {
"name-taken", "", map[string]string {"": name},
}
}
- u.store.byName[u.name] = nil
- u.store.byName[name] = u
+ u.store.byName[validate.Fold(u.name)] = nil
+ u.store.byName[validate.Fold(name)] = u
u.name = name
return nil
}
@@ -74,7 +89,7 @@ func (u *User) Delete() {
u.Stream.Event(proto.NewCmd("delete", u.id))
u.Stream.UnsubscribeAll()
- delete(u.store.byName, u.name)
+ delete(u.store.byName, validate.Fold(u.name))
u.store.world.RemoveObject(u.id)
gone := Tombstone {u.name}
diff --git a/server/validate/validate.go b/server/validate/validate.go
new file mode 100644
index 0000000..4415557
--- /dev/null
+++ b/server/validate/validate.go
@@ -0,0 +1,41 @@
+package validate
+
+import (
+ "strings"
+ "unicode"
+)
+
+func Name(name string) bool {
+ if len(Fold(name)) == 0 || len(name) >= 256 {
+ return false
+ }
+ for _, r := range name {
+ if unicode.IsControl(r) {
+ return false
+ }
+ }
+ return true
+}
+
+func Fold(s string) string {
+ var sb strings.Builder
+ var wasSpace bool
+ for _, r := range s {
+ for r < unicode.SimpleFold(r) {
+ r = unicode.SimpleFold(r)
+ }
+ if !unicode.IsPrint(r) {
+ continue
+ }
+ if r == ' ' {
+ if wasSpace {
+ continue
+ }
+ wasSpace = true
+ } else {
+ wasSpace = false
+ }
+ sb.WriteRune(r)
+ }
+ return strings.TrimSpace(sb.String())
+}