summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gomarkdown/markdown/internal/valid/valid.go
blob: 9b3de3ec04ad6f05fe17d72deda3f16c55960bdf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package valid

import (
	"bytes"
)

var URIs = [][]byte{
	[]byte("http://"),
	[]byte("https://"),
	[]byte("ftp://"),
	[]byte("mailto:"),
}

var Paths = [][]byte{
	[]byte("/"),
	[]byte("./"),
	[]byte("../"),
}

// TODO: documentation
func IsSafeURL(url []byte) bool {
	nLink := len(url)
	for _, path := range Paths {
		nPath := len(path)
		linkPrefix := url[:nPath]
		if nLink >= nPath && bytes.Equal(linkPrefix, path) {
			if nLink == nPath {
				return true
			} else if isAlnum(url[nPath]) {
				return true
			}
		}
	}

	for _, prefix := range URIs {
		// TODO: handle unicode here
		// case-insensitive prefix test
		nPrefix := len(prefix)
		if nLink > nPrefix {
			linkPrefix := bytes.ToLower(url[:nPrefix])
			if bytes.Equal(linkPrefix, prefix) && isAlnum(url[nPrefix]) {
				return true
			}
		}
	}

	return false
}

// isAlnum returns true if c is a digit or letter
// TODO: check when this is looking for ASCII alnum and when it should use unicode
func isAlnum(c byte) bool {
	return (c >= '0' && c <= '9') || isLetter(c)
}

// isLetter returns true if c is ascii letter
func isLetter(c byte) bool {
	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}