aboutsummaryrefslogtreecommitdiff
path: root/internal/onionloc/onionloc.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/onionloc/onionloc.go')
-rw-r--r--internal/onionloc/onionloc.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/internal/onionloc/onionloc.go b/internal/onionloc/onionloc.go
new file mode 100644
index 0000000..63e512a
--- /dev/null
+++ b/internal/onionloc/onionloc.go
@@ -0,0 +1,74 @@
+package onionloc
+
+import (
+ "net/http"
+ "strings"
+
+ "golang.org/x/net/html"
+)
+
+const (
+ HTTPHeaderName = "Onion-Location"
+)
+
+func HTTP(rsp *http.Response) (string, bool) {
+ v, ok := rsp.Header[HTTPHeaderName]
+ if !ok {
+ return "", false
+ }
+ if len(v) != 1 {
+ return "", false
+ }
+ return v[0], true
+}
+
+func HTML(rsp *http.Response) (string, bool) {
+ z := html.NewTokenizer(rsp.Body)
+ for {
+ tt := z.Next()
+ if tt == html.ErrorToken {
+ return "", false // EOF and other errors
+ }
+
+ switch tt {
+ case html.StartTagToken, html.SelfClosingTagToken:
+ t := z.Token()
+
+ // Looking for the html meta tag, see:
+ // https://www.w3schools.com/tags/tag_meta.asp
+ //
+ // We expect two attributes: "key" and "content"
+ if strings.ToLower(t.Data) != "meta" {
+ break
+ }
+ if len(t.Attr) != 2 {
+ break
+ }
+
+ // We're looking for the "http-equiv" key, see:
+ // https://www.w3schools.com/tags/att_meta_http_equiv.asp
+ //
+ // In particular with the value "onion-location", see:
+ // https://community.torproject.org/onion-services/advanced/onion-location/
+ //
+ // If we have all this and a following content
+ // attribute, that is the Onion-Location URL that this
+ // page advertises. We make no attempt to validate
+ // whether the content value is really an onion address.
+ attr := t.Attr[0]
+ if strings.ToLower(attr.Key) != "http-equiv" {
+ break
+ }
+ if strings.ToLower(attr.Val) != "onion-location" {
+ break
+ }
+ attr = t.Attr[1]
+ if strings.ToLower(attr.Key) != "content" {
+ break
+ }
+
+ return attr.Val, true
+ default:
+ }
+ }
+}