From 47d1010a531979799ac6ed09b1d7bc467117b8c4 Mon Sep 17 00:00:00 2001 From: Azareal Date: Thu, 20 Sep 2018 14:36:50 +1000 Subject: [PATCH] Added the AddHashLinkType function so that plugins can add custom hash link types in an efficient manner. Moved the hashLinkMap, etc. out of ParseMessage so that we can make them more pluggable. The first word in usernames can no longer be purely numeric. Added some ID mention tests. --- common/parser.go | 103 +++++++++++++++++++++++++--------------------- misc_test.go | 3 ++ routes/account.go | 15 +++++++ 3 files changed, 75 insertions(+), 46 deletions(-) diff --git a/common/parser.go b/common/parser.go index 60bf8976..cda043f3 100644 --- a/common/parser.go +++ b/common/parser.go @@ -398,6 +398,62 @@ func peekMatch(cur int, phrase string, runes []rune) bool { return true } +// ! Not concurrency safe +func AddHashLinkType(prefix string, handler func(*strings.Builder, string, *int)) { + // There can only be one hash link type starting with a specific character at the moment + hashType := hashLinkTypes[prefix[0]] + if hashType != "" { + return + } + hashLinkMap[prefix] = handler + hashLinkTypes[prefix[0]] = prefix +} + +func writeURL(sb *strings.Builder, url string, label string) { + sb.Write(URLOpen) + sb.WriteString(url) + sb.Write(URLOpen2) + sb.WriteString(label) + sb.Write(URLClose) +} + +var hashLinkTypes = []string{'t': "tid-", 'r': "rid-", 'f': "fid-"} +var hashLinkMap = map[string]func(*strings.Builder, string, *int){ + "tid-": func(sb *strings.Builder, msg string, i *int) { + tid, intLen := CoerceIntString(msg[*i:]) + *i += intLen + + topic, err := Topics.Get(tid) + if err != nil || !Forums.Exists(topic.ParentID) { + sb.Write(InvalidTopic) + return + } + writeURL(sb, BuildTopicURL("", tid), "#tid-"+strconv.Itoa(tid)) + }, + "rid-": func(sb *strings.Builder, msg string, i *int) { + rid, intLen := CoerceIntString(msg[*i:]) + *i += intLen + + topic, err := TopicByReplyID(rid) + if err != nil || !Forums.Exists(topic.ParentID) { + sb.Write(InvalidTopic) + return + } + writeURL(sb, BuildTopicURL("", topic.ID), "#rid-"+strconv.Itoa(rid)) + }, + "fid-": func(sb *strings.Builder, msg string, i *int) { + fid, intLen := CoerceIntString(msg[*i:]) + *i += intLen + + if !Forums.Exists(fid) { + sb.Write(InvalidForum) + return + } + writeURL(sb, BuildForumURL("", fid), "#fid-"+strconv.Itoa(fid)) + }, + // TODO: Forum Shortcode Link +} + // TODO: Write a test for this // TODO: We need a lot more hooks here. E.g. To add custom media types and handlers. // TODO: Use templates to reduce the amount of boilerplate? @@ -427,51 +483,6 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/) var sb strings.Builder var lastItem = 0 var i = 0 - - var writeURL = func(url string, label string) { - sb.Write(URLOpen) - sb.WriteString(url) - sb.Write(URLOpen2) - sb.WriteString(label) - sb.Write(URLClose) - } - var hashLinkTypes = []string{'t': "tid-", 'r': "rid-", 'f': "fid-"} - var hashLinkMap = map[string]func(){ - "tid-": func() { - tid, intLen := CoerceIntString(msg[i:]) - i += intLen - - topic, err := Topics.Get(tid) - if err != nil || !Forums.Exists(topic.ParentID) { - sb.Write(InvalidTopic) - return - } - writeURL(BuildTopicURL("", tid), "#tid-"+strconv.Itoa(tid)) - }, - "rid-": func() { - rid, intLen := CoerceIntString(msg[i:]) - i += intLen - - topic, err := TopicByReplyID(rid) - if err != nil || !Forums.Exists(topic.ParentID) { - sb.Write(InvalidTopic) - return - } - writeURL(BuildTopicURL("", topic.ID), "#rid-"+strconv.Itoa(rid)) - }, - "fid-": func() { - fid, intLen := CoerceIntString(msg[i:]) - i += intLen - - if !Forums.Exists(fid) { - sb.Write(InvalidForum) - return - } - writeURL(BuildForumURL("", fid), "#fid-"+strconv.Itoa(fid)) - }, - // TODO: Forum Shortcode Link - } - for ; len(msg) > (i + 1); i++ { if (i == 0 && (msg[0] > 32)) || ((msg[i] < 33) && (msg[i+1] > 32)) { if (i != 0) || msg[i] < 33 { @@ -485,7 +496,7 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/) if msg[i+1:len(hashType)+1] == hashType { sb.WriteString(msg[lastItem:i]) i += len(hashType) + 1 - hashLinkMap[hashType]() + hashLinkMap[hashType](&sb, msg, &i) lastItem = i } } else if msg[i] == '@' { diff --git a/misc_test.go b/misc_test.go index 878e8150..c71d0506 100644 --- a/misc_test.go +++ b/misc_test.go @@ -1262,6 +1262,9 @@ func TestParser(t *testing.T) { msgList = addMETri(msgList, "#tid-1", "#tid-1") msgList = addMETri(msgList, "https://github.com/Azareal/Gosora/#tid-1", "https://github.com/Azareal/Gosora/#tid-1") msgList = addMETri(msgList, "#fid-1", "#fid-1") + msgList = addMETri(msgList, "@1", "@Admin") + msgList = addMETri(msgList, "@0", "[Invalid Profile]") + msgList = addMETri(msgList, "@-1", "[Invalid Profile]1") for _, item := range msgList { res = common.ParseMessage(item.Msg, 1, "forums") diff --git a/routes/account.go b/routes/account.go index 4ca85fac..648364d9 100644 --- a/routes/account.go +++ b/routes/account.go @@ -212,6 +212,15 @@ func AccountRegister(w http.ResponseWriter, r *http.Request, user common.User) c return nil } +func isNumeric(data string) (numeric bool) { + for _, char := range data { + if char < 48 || char > 57 { + return false + } + } + return true +} + func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { headerLite, _ := common.SimpleUserCheck(w, r, &user) @@ -247,6 +256,12 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U regError("You didn't put in an email.", "no-email") } + // This is so a numeric name won't interfere with mentioning a user by ID, there might be a better way of doing this like perhaps !@ to mean IDs and @ to mean usernames in the pre-parser + usernameBits := strings.Split(username, " ") + if isNumeric(usernameBits[0]) { + regError("The first word of your name may not be purely numeric", "numeric-name") + } + ok := common.HasSuspiciousEmail(email) if ok { regError("Your email address is suspicious.", "suspicious-email")