[utils/handlers] Verify alias contains only unreserved URI chars
This commit is contained in:
parent
58c65bc261
commit
c25d50c35f
4 changed files with 40 additions and 23 deletions
|
@ -66,6 +66,11 @@ func (a *App) CreateShortURL(w http.ResponseWriter, r *http.Request) {
|
|||
http.Error(w, "Invalid URL", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Verify alias is valid
|
||||
if u.Alias != "" && !utils.IsValidAlias(u.Alias) {
|
||||
http.Error(w, "Invalid Alias", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Check if URL entry already exists
|
||||
existingURL := &URLEntry{}
|
||||
a.DB.Where("url = ?", u.URL).Find(existingURL)
|
||||
|
|
|
@ -80,6 +80,9 @@ func TestInvalidCreate(t *testing.T) {
|
|||
"no colon": {url: "http//google.com", alias: "ggl", status: http.StatusBadRequest},
|
||||
"empty": {url: "", alias: "", status: http.StatusBadRequest},
|
||||
"asdf": {url: "asdf", alias: "", status: http.StatusBadRequest},
|
||||
"spaces": {url: "https://google.com", alias: "oh no spaces", status: http.StatusBadRequest},
|
||||
"question mark": {url: "https://google.com", alias: "huh?", status: http.StatusBadRequest},
|
||||
"percent": {url: "https://google.com", alias: "test%20stuff", status: http.StatusBadRequest},
|
||||
}
|
||||
|
||||
app := setup()
|
||||
|
|
|
@ -2,22 +2,23 @@ package utils
|
|||
|
||||
import (
|
||||
"math/rand"
|
||||
"strings"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Alphanumeric charset
|
||||
const CHARSET = "abcdefghijklmnopqrstuvwxyz" +
|
||||
const (
|
||||
// Alphanumeric charset
|
||||
CHARSET = "abcdefghijklmnopqrstuvwxyz" +
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
// RFC 3986 Section 2.3 URI Unreserved Characters
|
||||
URIUnreservedChars = `^([A-Za-z0-9_.~-])+$`
|
||||
)
|
||||
|
||||
// Tests whether a string is in the alphanumeric charset
|
||||
func IsAlphaNum(str string) bool {
|
||||
for _, r := range []rune(str) {
|
||||
if !strings.ContainsRune(CHARSET, r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
func IsValidAlias(str string) bool {
|
||||
valid, err := regexp.MatchString(URIUnreservedChars, str)
|
||||
return valid && err == nil
|
||||
}
|
||||
|
||||
// Generate a random alphanumeric string of given length
|
||||
|
|
|
@ -4,23 +4,31 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestIsAlphaNum(t *testing.T) {
|
||||
func TestValidAlias(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
name string
|
||||
str string
|
||||
val bool
|
||||
}{
|
||||
"basic": {str: "hello", val: true},
|
||||
"dash": {str: "-", val: false},
|
||||
"period": {str: ".", val: false},
|
||||
"LOWERCASE": {str: "lowercase", val: true},
|
||||
"UPPERCASE": {str: "UPPERCASE", val: true},
|
||||
"underscore": {str: "_", val: true},
|
||||
"period": {str: ".", val: true},
|
||||
"dash": {str: "-", val: true},
|
||||
"tilde": {str: "~", val: true},
|
||||
"adsf": {str: "a_S-d.f~", val: true},
|
||||
"question mark": {str: "?", val: false},
|
||||
"backslash": {str: "?", val: false},
|
||||
"backslash": {str: "\\", val: false},
|
||||
"asterix": {str: "*", val: false},
|
||||
"ampersand": {str: "&", val: false},
|
||||
"space": {str: " ", val: false},
|
||||
"percent": {str: "%", val: false},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if IsAlphaNum(tc.str) != tc.val {
|
||||
t.Errorf("For '%s', expected %t. Got %t instead.", tc.str, tc.val, IsAlphaNum(tc.str))
|
||||
if IsValidAlias(tc.str) != tc.val {
|
||||
t.Errorf("For '%s', expected %t. Got %t instead.", tc.str, tc.val, IsValidAlias(tc.str))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -29,7 +37,7 @@ func TestIsAlphaNum(t *testing.T) {
|
|||
// For the code coverage why not
|
||||
func TestRandString(t *testing.T) {
|
||||
str := RandString(6)
|
||||
if len(str) == 6 && IsAlphaNum(str) {
|
||||
if len(str) == 6 && IsValidAlias(str) {
|
||||
return
|
||||
}
|
||||
t.Errorf("Seriously? How?")
|
||||
|
|
Loading…
Reference in a new issue