Merge tedu upstream
12 files changed, 160 insertions(+), 84 deletions(-)

M activity.go
M avatar.go
M docs/honk.8
M fun.go
M go.mod
M go.sum
M honk.go
M import.go
M views/account.html
M views/honkpage.js
M views/wonk.js
M web.go
M activity.go +12 -9
@@ 376,7 376,7 @@ var boxofboxes = cache.New(cache.Options
 	if err != nil {
 		dlog.Printf("need to get boxes for %s", ident)
 		var j junk.Junk
-		j, err = GetJunk(serverUID, ident)
+		j, err = GetJunk(readyLuserOne, ident)
 		if err != nil {
 			dlog.Printf("error getting boxes: %s", err)
 			return nil, false

          
@@ 546,6 546,7 @@ func xonksaver(user *WhatAbout, item jun
 		var xid, rid, url, convoy string
 		var replies []string
 		var obj junk.Junk
+		waspage := false
 		switch what {
 		case "Delete":
 			obj, ok = item.GetMap("object")

          
@@ 654,6 655,9 @@ func xonksaver(user *WhatAbout, item jun
 		case "Move":
 			obj = item
 			what = "move"
+		case "Page":
+			waspage = true
+			fallthrough
 		case "GuessWord": // dealt with below
 			fallthrough
 		case "Audio":

          
@@ 667,8 671,6 @@ func xonksaver(user *WhatAbout, item jun
 		case "Note":
 			fallthrough
 		case "Article":
-			fallthrough
-		case "Page":
 			obj = item
 			what = "honk"
 		case "Event":

          
@@ 741,6 743,10 @@ func xonksaver(user *WhatAbout, item jun
 			if sens, _ := obj["sensitive"].(bool); sens && precis == "" {
 				precis = "unspecified horror"
 			}
+			if waspage {
+				content += fmt.Sprintf(`<p><a href="%s">%s</a>`, url, url)
+				url = xid
+			}
 			rid, ok = obj.GetString("inReplyTo")
 			if !ok {
 				if robj, ok := obj.GetMap("inReplyTo"); ok {

          
@@ 1479,7 1485,7 @@ func doesitmatter(what string) bool {
 func collectiveaction(honk *Honk) {
 	user := getserveruser()
 	for _, ont := range honk.Onts {
-		dubs := getnameddubs(serverUID, ont)
+		dubs := getnameddubs(readyLuserOne, ont)
 		if len(dubs) == 0 {
 			continue
 		}

          
@@ 1541,9 1547,6 @@ func junkuser(user *WhatAbout) junk.Junk
 			a["url"] = ava
 		} else {
 			u := fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL))
-			if user.Options.Avahex {
-				u += "&hex=1"
-			}
 			a["url"] = u
 		}
 		j["icon"] = a

          
@@ 1596,7 1599,7 @@ var handfull = cache.New(cache.Options{F
 		return href, true
 	}
 	dlog.Printf("fishing for %s", name)
-	j, err := GetJunkFast(serverUID, fmt.Sprintf("https://%s/.well-known/webfinger?resource=acct:%s", m[1], name))
+	j, err := GetJunkFast(readyLuserOne, fmt.Sprintf("https://%s/.well-known/webfinger?resource=acct:%s", m[1], name))
 	if err != nil {
 		ilog.Printf("failed to go fish %s: %s", name, err)
 		return "", true

          
@@ 1641,7 1644,7 @@ func investigate(name string) (*SomeThin
 	if name == "" {
 		return nil, fmt.Errorf("no name")
 	}
-	obj, err := GetJunkFast(serverUID, name)
+	obj, err := GetJunkFast(readyLuserOne, name)
 	if err != nil {
 		return nil, err
 	}

          
M avatar.go +1 -22
@@ 65,7 65,7 @@ func loadAvatarColors() {
 	}
 }
 
-func genAvatar(name string, hex bool) []byte {
+func genAvatar(name string) []byte {
 	h := sha512.New()
 	h.Write([]byte(name))
 	s := h.Sum(nil)

          
@@ 73,27 73,6 @@ func genAvatar(name string, hex bool) []
 	for i := 0; i < 64; i++ {
 		for j := 0; j < 64; j++ {
 			p := i*img.Stride + j*4
-			if hex {
-				tan := 0.577
-				if i < 32 {
-					if j < 17-int(float64(i)*tan) || j > 46+int(float64(i)*tan) {
-						img.Pix[p+0] = 0
-						img.Pix[p+1] = 0
-						img.Pix[p+2] = 0
-						img.Pix[p+3] = 255
-						continue
-					}
-				} else {
-					if j < 17-int(float64(64-i)*tan) || j > 46+int(float64(64-i)*tan) {
-						img.Pix[p+0] = 0
-						img.Pix[p+1] = 0
-						img.Pix[p+2] = 0
-						img.Pix[p+3] = 255
-						continue
-
-					}
-				}
-			}
 			xx := i/16*16 + j/16
 			x := s[xx]
 			if x < 64 {

          
M docs/honk.8 +1 -1
@@ 41,7 41,7 @@ proxy_set_header Host $http_host;
 .Ss Build
 Building
 .Nm
-requires a go compiler 1.13 and libsqlite.
+requires a go compiler 1.16 and libsqlite.
 On
 .Ox
 this is the go and sqlite3 packages.

          
M fun.go +1 -1
@@ 643,7 643,7 @@ var zaggies = cache.New(cache.Options{Fi
 	data := getxonker(keyname, "pubkey")
 	if data == "" {
 		dlog.Printf("hitting the webs for missing pubkey: %s", keyname)
-		j, err := GetJunk(serverUID, keyname)
+		j, err := GetJunk(readyLuserOne, keyname)
 		if err != nil {
 			ilog.Printf("error getting %s pubkey: %s", keyname, err)
 			when := time.Now().UTC().Format(dbtimeformat)

          
M go.mod +1 -1
@@ 9,5 9,5 @@ require (
 	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
 	golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
 	humungus.tedunangst.com/r/go-sqlite3 v1.1.3
-	humungus.tedunangst.com/r/webs v0.6.57
+	humungus.tedunangst.com/r/webs v0.6.59
 )

          
M go.sum +2 -2
@@ 25,5 25,5 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI=
 humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
-humungus.tedunangst.com/r/webs v0.6.57 h1:HzYgzknJTL54KJKeRUwVvyYAsUSCHl+ImcMI0lIzan4=
-humungus.tedunangst.com/r/webs v0.6.57/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc=
+humungus.tedunangst.com/r/webs v0.6.59 h1:zOlBGZqrRo22QND1CN8HbhEv3JwoiZkspi7TgVuJS0s=
+humungus.tedunangst.com/r/webs v0.6.59/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc=

          
M honk.go +1 -1
@@ 53,7 53,6 @@ type WhatAbout struct {
 type UserOptions struct {
 	SkinnyCSS  bool   `json:",omitempty"`
 	OmitImages bool   `json:",omitempty"`
-	Avahex     bool   `json:",omitempty"`
 	MentionAll bool   `json:",omitempty"`
 	Avatar     string `json:",omitempty"`
 	Banner     string `json:",omitempty"`

          
@@ 69,6 68,7 @@ type KeyInfo struct {
 }
 
 const serverUID int64 = -2
+const readyLuserOne int64 = 1
 
 type Honk struct {
 	ID       int64

          
M import.go +136 -35
@@ 21,6 21,7 @@ import (
 	"fmt"
 	"html"
 	"io/ioutil"
+	"log"
 	"os"
 	"regexp"
 	"sort"

          
@@ 223,26 224,118 @@ func importTwitter(username, source stri
 	}
 
 	type Tweet struct {
-		ID_str                  string
-		Created_at              string
-		Full_text               string
-		In_reply_to_screen_name string
-		In_reply_to_status_id   string
-		Entities                struct {
-			Hashtags []struct {
-				Text string
-			}
-			Media []struct {
-				Url       string
-				Media_url string
-			}
-			Urls []struct {
-				Url          string
-				Expanded_url string
-			}
-		}
 		date   time.Time
 		convoy string
+		Tweet  struct {
+			CreatedAt        string   `json:"created_at"`
+			DisplayTextRange []string `json:"display_text_range"`
+			EditInfo         struct {
+				Initial struct {
+					EditTweetIds   []string `json:"editTweetIds"`
+					EditableUntil  string   `json:"editableUntil"`
+					EditsRemaining string   `json:"editsRemaining"`
+					IsEditEligible bool     `json:"isEditEligible"`
+				} `json:"initial"`
+			} `json:"edit_info"`
+			Entities struct {
+				Hashtags []struct {
+					Indices []string `json:"indices"`
+					Text    string   `json:"text"`
+				} `json:"hashtags"`
+				Media []struct {
+					DisplayURL    string   `json:"display_url"`
+					ExpandedURL   string   `json:"expanded_url"`
+					ID            string   `json:"id"`
+					IdStr         string   `json:"id_str"`
+					Indices       []string `json:"indices"`
+					MediaURL      string   `json:"media_url"`
+					MediaUrlHttps string   `json:"media_url_https"`
+					Sizes         struct {
+						Large struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"large"`
+						Medium struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"medium"`
+						Small struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"small"`
+						Thumb struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"thumb"`
+					} `json:"sizes"`
+					Type string `json:"type"`
+					URL  string `json:"url"`
+				} `json:"media"`
+				Symbols []interface{} `json:"symbols"`
+				Urls    []struct {
+					DisplayURL  string   `json:"display_url"`
+					ExpandedURL string   `json:"expanded_url"`
+					Indices     []string `json:"indices"`
+					URL         string   `json:"url"`
+				} `json:"urls"`
+				UserMentions []interface{} `json:"user_mentions"`
+			} `json:"entities"`
+			ExtendedEntities struct {
+				Media []struct {
+					DisplayURL    string   `json:"display_url"`
+					ExpandedURL   string   `json:"expanded_url"`
+					ID            string   `json:"id"`
+					IdStr         string   `json:"id_str"`
+					Indices       []string `json:"indices"`
+					MediaURL      string   `json:"media_url"`
+					MediaUrlHttps string   `json:"media_url_https"`
+					Sizes         struct {
+						Large struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"large"`
+						Medium struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"medium"`
+						Small struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"small"`
+						Thumb struct {
+							H      string `json:"h"`
+							Resize string `json:"resize"`
+							W      string `json:"w"`
+						} `json:"thumb"`
+					} `json:"sizes"`
+					Type string `json:"type"`
+					URL  string `json:"url"`
+				} `json:"media"`
+			} `json:"extended_entities"`
+			FavoriteCount        string `json:"favorite_count"`
+			Favorited            bool   `json:"favorited"`
+			FullText             string `json:"full_text"`
+			ID                   string `json:"id"`
+			IdStr                string `json:"id_str"`
+			InReplyToScreenName  string `json:"in_reply_to_screen_name"`
+			InReplyToStatusID    string `json:"in_reply_to_status_id"`
+			InReplyToStatusIdStr string `json:"in_reply_to_status_id_str"`
+			InReplyToUserID      string `json:"in_reply_to_user_id"`
+			InReplyToUserIdStr   string `json:"in_reply_to_user_id_str"`
+			Lang                 string `json:"lang"`
+			PossiblySensitive    bool   `json:"possibly_sensitive"`
+			RetweetCount         string `json:"retweet_count"`
+			Retweeted            bool   `json:"retweeted"`
+			Source               string `json:"source"`
+			Truncated            bool   `json:"truncated"`
+		} `json:"tweet"`
 	}
 
 	var tweets []*Tweet

          
@@ 260,8 353,8 @@ func importTwitter(username, source stri
 	fd.Close()
 	tweetmap := make(map[string]*Tweet)
 	for _, t := range tweets {
-		t.date, _ = time.Parse("Mon Jan 02 15:04:05 -0700 2006", t.Created_at)
-		tweetmap[t.ID_str] = t
+		t.date, _ = time.Parse("Mon Jan 02 15:04:05 -0700 2006", t.Tweet.CreatedAt)
+		tweetmap[t.Tweet.IdStr] = t
 	}
 	sort.Slice(tweets, func(i, j int) bool {
 		return tweets[i].date.Before(tweets[j].date)

          
@@ 271,26 364,33 @@ func importTwitter(username, source stri
 		row := stmtFindXonk.QueryRow(user.ID, xid)
 		err := row.Scan(&id)
 		if err == nil {
+			log.Printf("id = %v", id)
 			return true
 		}
 		return false
 	}
-
+	log.Printf("importing %v tweets", len(tweets))
 	for _, t := range tweets {
-		xid := fmt.Sprintf("%s/%s/%s", user.URL, honkSep, t.ID_str)
+		xid := fmt.Sprintf("%s/%s/%s", user.URL, honkSep, t.Tweet.IdStr)
 		if havetwid(xid) {
 			continue
 		}
+
+		if t.Tweet.FavoriteCount == "0" || t.Tweet.FavoriteCount == "" {
+			log.Printf("skipping, unworthy tweet")
+			continue
+		}
+
 		what := "honk"
 		noise := ""
-		if parent := tweetmap[t.In_reply_to_status_id]; parent != nil {
+		if parent := tweetmap[t.Tweet.InReplyToStatusID]; parent != nil {
 			t.convoy = parent.convoy
 			what = "tonk"
 		} else {
-			t.convoy = "data:,acoustichonkytonk-" + t.ID_str
-			if t.In_reply_to_screen_name != "" {
+			t.convoy = "data:,acoustichonkytonk-" + t.Tweet.IdStr
+			if t.Tweet.InReplyToScreenName != "" {
 				noise = fmt.Sprintf("re: https://twitter.com/%s/status/%s\n\n",
-					t.In_reply_to_screen_name, t.In_reply_to_status_id)
+					t.Tweet.InReplyToScreenName, t.Tweet.InReplyToStatusID)
 				what = "tonk"
 			}
 		}

          
@@ 308,17 408,17 @@ func importTwitter(username, source stri
 			Public:   true,
 			Whofore:  2,
 		}
-		noise += t.Full_text
+		noise += t.Tweet.FullText
 		// unbelievable
 		noise = html.UnescapeString(noise)
-		for _, r := range t.Entities.Urls {
-			noise = strings.Replace(noise, r.Url, r.Expanded_url, -1)
+		for _, r := range t.Tweet.Entities.Urls {
+			noise = strings.Replace(noise, r.URL, r.ExpandedURL, -1)
 		}
-		for _, m := range t.Entities.Media {
-			u := m.Media_url
+		for _, m := range t.Tweet.Entities.Media {
+			u := m.MediaURL
 			idx := strings.LastIndexByte(u, '/')
 			u = u[idx+1:]
-			fname := fmt.Sprintf("%s/tweet_media/%s-%s", source, t.ID_str, u)
+			fname := fmt.Sprintf("%s/tweets_media/%s-%s", source, t.Tweet.IdStr, u)
 			data, err := ioutil.ReadFile(fname)
 			if err != nil {
 				elog.Printf("error reading media: %s", fname)

          
@@ 335,12 435,13 @@ func importTwitter(username, source stri
 				FileID: fileid,
 			}
 			honk.Donks = append(honk.Donks, donk)
-			noise = strings.Replace(noise, m.Url, "", -1)
+			noise = strings.Replace(noise, m.URL, "", -1)
 		}
-		for _, ht := range t.Entities.Hashtags {
+		for _, ht := range t.Tweet.Entities.Hashtags {
 			honk.Onts = append(honk.Onts, "#"+ht.Text)
 		}
 		honk.Noise = noise
-		savehonk(&honk)
+		err := savehonk(&honk)
+		log.Printf("honk saved %v -> %v", xid, err)
 	}
 }

          
M views/account.html +0 -2
@@ 10,8 10,6 @@ 
 <p><textarea name="whatabout">{{ .WhatAbout }}</textarea>
 <p><label class="button" for="skinny">skinny layout:</label>
 <input tabindex=1 type="checkbox" id="skinny" name="skinny" value="skinny" {{ if .User.Options.SkinnyCSS }}checked{{ end }}><span></span>
-<p><label class="button" for="avahex">hex avatar:</label>
-<input tabindex=1 type="checkbox" id="avahex" name="avahex" value="avahex" {{ if .User.Options.Avahex }}checked{{ end }}><span></span>
 <p><label class="button" for="omitimages">omit images:</label>
 <input tabindex=1 type="checkbox" id="omitimages" name="omitimages" value="omitimages" {{ if .User.Options.OmitImages }}checked{{ end }}><span></span>
 <p><label class="button" for="mentionall">mention all:</label>

          
M views/honkpage.js +1 -1
@@ 2,7 2,7 @@ function encode(hash) {
         var s = []
         for (var key in hash) {
                 var val = hash[key]
-                s.push(escape(key) + "=" + escape(val))
+                s.push(encodeURIComponent(key) + "=" + encodeURIComponent(val))
         }
         return s.join("&")
 }

          
M views/wonk.js +1 -1
@@ 6,7 6,7 @@ export function addguesscontrols(elem, w
 	host.guesses = []
 	host.xid = xid
 	var xhr = new XMLHttpRequest()
-        xhr.open("GET", "/bloat/wonkles?w=" + escape(wordlist))
+        xhr.open("GET", "/bloat/wonkles?w=" + encodeURIComponent(wordlist))
         xhr.responseType = "json"
         xhr.onload = function() { 
 		var wordlist = xhr.response.wordlist

          
M web.go +3 -8
@@ 122,6 122,7 @@ func homepage(w http.ResponseWriter, r *
 			honks = gethonksforme(userid, 0)
 			honks = osmosis(honks, userid, false)
 			menewnone(userid)
+			templinfo["UserInfo"], _ = butwhatabout(u.Username)
 		case "/longago":
 			templinfo["ServerMessage"] = "long ago and far away!"
 			templinfo["PageName"] = "longago"

          
@@ 1124,11 1125,6 @@ func saveuser(w http.ResponseWriter, r *
 	} else {
 		options.SkinnyCSS = false
 	}
-	if r.FormValue("avahex") == "avahex" {
-		options.Avahex = true
-	} else {
-		options.Avahex = false
-	}
 	if r.FormValue("omitimages") == "omitimages" {
 		options.OmitImages = true
 	} else {

          
@@ 2217,9 2213,8 @@ func isURL(s string) bool {
 }
 
 func avatateautogen(w http.ResponseWriter, r *http.Request) {
-	hex := r.FormValue("hex") == "1"
 	n := r.FormValue("a")
-	a := genAvatar(n, hex)
+	a := genAvatar(n)
 	if !develMode {
 		w.Header().Set("Cache-Control", "max-age="+somedays())
 	}

          
@@ 2630,7 2625,7 @@ func emuinit() {
 
 func serve() {
 	db := opendatabase()
-	login.Init(login.InitArgs{Db: db, Logger: ilog, Insecure: develMode})
+	login.Init(login.InitArgs{Db: db, Logger: ilog, Insecure: develMode, SameSiteStrict: !develMode})
 
 	listener, err := openListener()
 	if err != nil {