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