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")