|
|
|
@ -11,22 +11,19 @@ import (
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type Capsule struct {
|
|
|
|
|
MimeMaj string
|
|
|
|
|
MimeMaj string
|
|
|
|
|
MimeMin string
|
|
|
|
|
Status int
|
|
|
|
|
Content string
|
|
|
|
|
Status int
|
|
|
|
|
Content string
|
|
|
|
|
Links []string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type TofuDigest struct {
|
|
|
|
|
certs map[string]string
|
|
|
|
|
ClientCert tls.Certificate
|
|
|
|
|
certs map[string]string
|
|
|
|
|
ClientCert tls.Certificate
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------\\
|
|
|
|
|
// + + + R E C E I V E R S + + + \\
|
|
|
|
|
//--------------------------------------------------\\
|
|
|
|
@ -107,17 +104,17 @@ func (t *TofuDigest) newCert(host string, cState *tls.ConnectionState) error {
|
|
|
|
|
reasons.WriteString("; ")
|
|
|
|
|
}
|
|
|
|
|
if now.Before(cert.NotBefore) {
|
|
|
|
|
reasons.WriteString(fmt.Sprintf("Cert [%d] is not valid yet", index + 1))
|
|
|
|
|
reasons.WriteString(fmt.Sprintf("Cert [%d] is not valid yet", index+1))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if now.After(cert.NotAfter) {
|
|
|
|
|
reasons.WriteString(fmt.Sprintf("Cert [%d] is expired", index + 1))
|
|
|
|
|
reasons.WriteString(fmt.Sprintf("Cert [%d] is expired", index+1))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := cert.VerifyHostname(host); err != nil {
|
|
|
|
|
reasons.WriteString(fmt.Sprintf("Cert [%d] hostname does not match", index + 1))
|
|
|
|
|
reasons.WriteString(fmt.Sprintf("Cert [%d] hostname does not match", index+1))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -143,8 +140,6 @@ func (t *TofuDigest) IniDump() string {
|
|
|
|
|
return out.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------\\
|
|
|
|
|
// + + + F U N C T I O N S + + + \\
|
|
|
|
|
//--------------------------------------------------\\
|
|
|
|
@ -157,7 +152,7 @@ func Retrieve(host, port, resource string, td *TofuDigest) (string, error) {
|
|
|
|
|
addr := host + ":" + port
|
|
|
|
|
|
|
|
|
|
conf := &tls.Config{
|
|
|
|
|
MinVersion: tls.VersionTLS12,
|
|
|
|
|
MinVersion: tls.VersionTLS12,
|
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -183,7 +178,7 @@ func Retrieve(host, port, resource string, td *TofuDigest) (string, error) {
|
|
|
|
|
|
|
|
|
|
if td.Exists(host) {
|
|
|
|
|
// See if we have a matching cert
|
|
|
|
|
err := td.Match(host, &connState)
|
|
|
|
|
err := td.Match(host, &connState)
|
|
|
|
|
if err != nil && err.Error() != "EXP" {
|
|
|
|
|
// If there is no match and it isnt because of an expiration
|
|
|
|
|
// just return the error
|
|
|
|
@ -223,21 +218,21 @@ func Fetch(host, port, resource string, td *TofuDigest) ([]byte, error) {
|
|
|
|
|
rawResp, err := Retrieve(host, port, resource, td)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return make([]byte, 0), err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp := strings.SplitN(rawResp, "\r\n", 2)
|
|
|
|
|
if len(resp) != 2 {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return make([]byte, 0), fmt.Errorf("Invalid response from server")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
header := strings.SplitN(resp[0], " ", 2)
|
|
|
|
|
if len([]rune(header[0])) != 2 {
|
|
|
|
|
header = strings.SplitN(resp[0], "\t", 2)
|
|
|
|
|
if len([]rune(header[0])) != 2 {
|
|
|
|
|
return make([]byte,0), fmt.Errorf("Invalid response format from server")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return make([]byte, 0), fmt.Errorf("Invalid response format from server")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get status code single digit form
|
|
|
|
|
status, err := strconv.Atoi(string(header[0][0]))
|
|
|
|
@ -271,24 +266,24 @@ func Visit(host, port, resource string, td *TofuDigest) (Capsule, error) {
|
|
|
|
|
rawResp, err := Retrieve(host, port, resource, td)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return capsule, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp := strings.SplitN(rawResp, "\r\n", 2)
|
|
|
|
|
if len(resp) != 2 {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return capsule, fmt.Errorf("Invalid response from server")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
header := strings.SplitN(resp[0], " ", 2)
|
|
|
|
|
if len([]rune(header[0])) != 2 {
|
|
|
|
|
header = strings.SplitN(resp[0], "\t", 2)
|
|
|
|
|
if len([]rune(header[0])) != 2 {
|
|
|
|
|
return capsule, fmt.Errorf("Invalid response format from server")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body := resp[1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get status code single digit form
|
|
|
|
|
capsule.Status, err = strconv.Atoi(string(header[0][0]))
|
|
|
|
|
if err != nil {
|
|
|
|
@ -351,7 +346,7 @@ func parseGemini(b, rootUrl, currentUrl string) (string, []string) {
|
|
|
|
|
subLn := strings.Trim(ln[2:], "\r\n\t \a")
|
|
|
|
|
splitPoint := strings.IndexAny(subLn, " \t")
|
|
|
|
|
|
|
|
|
|
if splitPoint < 0 || len([]rune(subLn)) - 1 <= splitPoint {
|
|
|
|
|
if splitPoint < 0 || len([]rune(subLn))-1 <= splitPoint {
|
|
|
|
|
link = subLn
|
|
|
|
|
decorator = subLn
|
|
|
|
|
} else {
|
|
|
|
@ -359,7 +354,7 @@ func parseGemini(b, rootUrl, currentUrl string) (string, []string) {
|
|
|
|
|
decorator = strings.Trim(subLn[splitPoint:], "\t\n\r \a")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.Index(link, "://") < 0 {
|
|
|
|
|
if strings.Index(link, "://") < 0 {
|
|
|
|
|
link = handleRelativeUrl(link, rootUrl, currentUrl)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -385,7 +380,7 @@ func handleRelativeUrl(u, root, current string) string {
|
|
|
|
|
return fmt.Sprintf("%s/%s", root, u)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current[:ind + 1]
|
|
|
|
|
current = current[:ind+1]
|
|
|
|
|
return fmt.Sprintf("%s%s", current, u)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -398,7 +393,6 @@ func hashCert(cert []byte) string {
|
|
|
|
|
return fmt.Sprintf("%s", string(bytes.Join(hex, []byte(":"))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func MakeCapsule() Capsule {
|
|
|
|
|
return Capsule{"", "", 0, "", make([]string, 0, 5)}
|
|
|
|
|
}
|
|
|
|
|