Merge remote-tracking branch 'upstream/master'

Bring on the newness
master
Jason Staten 1 year ago
commit aee97f0395

@ -27,6 +27,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"regexp"
"strings" "strings"
"time" "time"
@ -371,7 +372,7 @@ var boxofboxes = cache.New(cache.Options{Filler: func(ident string) (*Box, bool)
if err != nil { if err != nil {
dlog.Printf("need to get boxes for %s", ident) dlog.Printf("need to get boxes for %s", ident)
var j junk.Junk var j junk.Junk
j, err = GetJunk(serverUID, ident) j, err = GetJunk(readyLuserOne, ident)
if err != nil { if err != nil {
dlog.Printf("error getting boxes: %s", err) dlog.Printf("error getting boxes: %s", err)
return nil, false return nil, false
@ -506,6 +507,39 @@ func firstofmany(obj junk.Junk, key string) string {
return "" return ""
} }
var re_mast0link = regexp.MustCompile(`https://[[:alnum:].]+/users/[[:alnum:]]+/statuses/[[:digit:]]+`)
var re_masto1ink = regexp.MustCompile(`https://[[:alnum:].]+/@[[:alnum:]]+/[[:digit:]]+`)
var re_misslink = regexp.MustCompile(`https://[[:alnum:].]+/notes/[[:alnum:]]+`)
var re_honklink = regexp.MustCompile(`https://[[:alnum:].]+/u/[[:alnum:]]+/h/[[:alnum:]]+`)
var re_romalink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
var re_qtlinks = regexp.MustCompile(`>https://[^\s<]+<`)
func qutify(user *WhatAbout, content string) string {
// well this is gross
malcontent := strings.ReplaceAll(content, `</span><span class="ellipsis">`, "")
malcontent = strings.ReplaceAll(malcontent, `</span><span class="invisible">`, "")
mlinks := re_qtlinks.FindAllString(malcontent, -1)
for _, m := range mlinks {
m = m[1 : len(m)-1]
dlog.Printf("consider qt: %s", m)
if re_mast0link.MatchString(m) ||
re_masto1ink.MatchString(m) ||
re_misslink.MatchString(m) ||
re_honklink.MatchString(m) ||
re_romalink.MatchString(m) {
j, err := GetJunk(user.ID, m)
dlog.Printf("fetched %s: %s", m, err)
if err == nil {
q, ok := j.GetString("content")
if ok {
content = fmt.Sprintf("%s<blockquote>%s</blockquote>", content, q)
}
}
}
}
return content
}
func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
depth := 0 depth := 0
maxdepth := 10 maxdepth := 10
@ -541,6 +575,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
var xid, rid, url, convoy string var xid, rid, url, convoy string
var replies []string var replies []string
var obj junk.Junk var obj junk.Junk
waspage := false
switch what { switch what {
case "Delete": case "Delete":
obj, ok = item.GetMap("object") obj, ok = item.GetMap("object")
@ -649,7 +684,8 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
case "Move": case "Move":
obj = item obj = item
what = "move" what = "move"
case "GuessWord": // dealt with below case "Page":
waspage = true
fallthrough fallthrough
case "Audio": case "Audio":
fallthrough fallthrough
@ -662,8 +698,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
case "Note": case "Note":
fallthrough fallthrough
case "Article": case "Article":
fallthrough
case "Page":
obj = item obj = item
what = "honk" what = "honk"
case "Event": case "Event":
@ -688,9 +722,11 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
return nil return nil
} }
if originate(xid) != origin { if originate(xid) != origin {
ilog.Printf("original sin: %s not from %s", xid, origin) if !develMode && origin != "" {
item.Write(ilog.Writer()) ilog.Printf("original sin: %s not from %s", xid, origin)
return nil item.Write(ilog.Writer())
return nil
}
} }
var xonk Honk var xonk Honk
@ -736,6 +772,13 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
if sens, _ := obj["sensitive"].(bool); sens && precis == "" { if sens, _ := obj["sensitive"].(bool); sens && precis == "" {
precis = "unspecified horror" precis = "unspecified horror"
} }
if waspage {
content += fmt.Sprintf(`<p><a href="%s">%s</a>`, url, url)
url = xid
}
if user.Options.InlineQuotes {
content = qutify(user, content)
}
rid, ok = obj.GetString("inReplyTo") rid, ok = obj.GetString("inReplyTo")
if !ok { if !ok {
if robj, ok := obj.GetMap("inReplyTo"); ok { if robj, ok := obj.GetMap("inReplyTo"); ok {
@ -775,12 +818,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
targ, _ := obj.GetString("target") targ, _ := obj.GetString("target")
content += string(templates.Sprintf(`<p>Moved to <a href="%s">%s</a>`, targ, targ)) content += string(templates.Sprintf(`<p>Moved to <a href="%s">%s</a>`, targ, targ))
} }
if ot == "GuessWord" {
what = "wonk"
content, _ = obj.GetString("content")
xonk.Wonkles, _ = obj.GetString("wordlist")
go savewonkles(xonk.Wonkles)
}
if what == "honk" && rid != "" { if what == "honk" && rid != "" {
what = "tonk" what = "tonk"
} }
@ -1136,8 +1173,6 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
fallthrough fallthrough
case "event": case "event":
fallthrough fallthrough
case "wonk":
fallthrough
case "honk": case "honk":
j["type"] = "Create" j["type"] = "Create"
jo = junk.New() jo = junk.New()
@ -1145,8 +1180,6 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
jo["type"] = "Note" jo["type"] = "Note"
if h.What == "event" { if h.What == "event" {
jo["type"] = "Event" jo["type"] = "Event"
} else if h.What == "wonk" {
jo["type"] = "GuessWord"
} }
if h.What == "update" { if h.What == "update" {
j["type"] = "Update" j["type"] = "Update"
@ -1253,9 +1286,6 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
jo["duration"] = "PT" + strings.ToUpper(t.Duration.String()) jo["duration"] = "PT" + strings.ToUpper(t.Duration.String())
} }
} }
if w := h.Wonkles; w != "" {
jo["wordlist"] = w
}
atts := activatedonks(h.Donks) atts := activatedonks(h.Donks)
if len(atts) > 0 { if len(atts) > 0 {
jo["attachment"] = atts jo["attachment"] = atts
@ -1474,7 +1504,7 @@ func doesitmatter(what string) bool {
func collectiveaction(honk *Honk) { func collectiveaction(honk *Honk) {
user := getserveruser() user := getserveruser()
for _, ont := range honk.Onts { for _, ont := range honk.Onts {
dubs := getnameddubs(serverUID, ont) dubs := getnameddubs(readyLuserOne, ont)
if len(dubs) == 0 { if len(dubs) == 0 {
continue continue
} }
@ -1536,9 +1566,6 @@ func junkuser(user *WhatAbout) junk.Junk {
a["url"] = ava a["url"] = ava
} else { } else {
u := fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL)) u := fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL))
if user.Options.Avahex {
u += "&hex=1"
}
a["url"] = u a["url"] = u
} }
j["icon"] = a j["icon"] = a
@ -1591,7 +1618,7 @@ var handfull = cache.New(cache.Options{Filler: func(name string) (string, bool)
return href, true return href, true
} }
dlog.Printf("fishing for %s", name) 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 { if err != nil {
ilog.Printf("failed to go fish %s: %s", name, err) ilog.Printf("failed to go fish %s: %s", name, err)
return "", true return "", true
@ -1636,7 +1663,7 @@ func investigate(name string) (*SomeThing, error) {
if name == "" { if name == "" {
return nil, fmt.Errorf("no name") return nil, fmt.Errorf("no name")
} }
obj, err := GetJunkFast(serverUID, name) obj, err := GetJunkFast(readyLuserOne, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1901,7 +1928,7 @@ func followyou2(user *WhatAbout, j junk.Junk) {
ilog.Printf("updating honker accept: %s", who) ilog.Printf("updating honker accept: %s", who)
db := opendatabase() db := opendatabase()
row := db.QueryRow("select name, folxid from honkers where userid = ? and xid = ? and flavor in ('presub')", row := db.QueryRow("select name, folxid from honkers where userid = ? and xid = ? and flavor in ('presub', 'sub')",
user.ID, who) user.ID, who)
var name, folxid string var name, folxid string
err := row.Scan(&name, &folxid) err := row.Scan(&name, &folxid)

@ -65,7 +65,7 @@ func loadAvatarColors() {
} }
} }
func genAvatar(name string, hex bool) []byte { func genAvatar(name string) []byte {
h := sha512.New() h := sha512.New()
h.Write([]byte(name)) h.Write([]byte(name))
s := h.Sum(nil) s := h.Sum(nil)
@ -73,27 +73,6 @@ func genAvatar(name string, hex bool) []byte {
for i := 0; i < 64; i++ { for i := 0; i < 64; i++ {
for j := 0; j < 64; j++ { for j := 0; j < 64; j++ {
p := i*img.Stride + j*4 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 xx := i/16*16 + j/16
x := s[xx] x := s[xx]
if x < 64 { if x < 64 {

@ -14,54 +14,3 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package main package main
import (
"net/http"
"strings"
"humungus.tedunangst.com/r/webs/junk"
)
func servewonkles(w http.ResponseWriter, r *http.Request) {
url := r.FormValue("w")
dlog.Printf("getting wordlist: %s", url)
wonkles := getxonker(url, "wonkles")
if wonkles == "" {
wonkles = savewonkles(url)
if wonkles == "" {
http.NotFound(w, r)
return
}
}
var words []string
for _, l := range strings.Split(wonkles, "\n") {
words = append(words, l)
}
if !develMode {
w.Header().Set("Cache-Control", "max-age=7776000")
}
j := junk.New()
j["wordlist"] = words
j.Write(w)
}
func savewonkles(url string) string {
w := getxonker(url, "wonkles")
if w != "" {
return w
}
ilog.Printf("fetching wonkles: %s", url)
res, err := fetchsome(url)
if err != nil {
ilog.Printf("error fetching wonkles: %s", err)
return ""
}
w = getxonker(url, "wonkles")
if w != "" {
return w
}
w = string(res)
savexonker(url, w, "wonkles", "")
return w
}

@ -437,9 +437,7 @@ func donksforhonks(honks []*Honk) {
continue continue
} }
case "wonkles": case "wonkles":
h.Wonkles = j
case "guesses": case "guesses":
h.Guesses = template.HTML(j)
case "oldrev": case "oldrev":
default: default:
elog.Printf("unknown meta genus: %s", genus) elog.Printf("unknown meta genus: %s", genus)
@ -849,20 +847,6 @@ func saveextras(tx *sql.Tx, h *Honk) error {
return err return err
} }
} }
if w := h.Wonkles; w != "" {
_, err := tx.Stmt(stmtSaveMeta).Exec(h.ID, "wonkles", w)
if err != nil {
elog.Printf("error saving wonkles: %s", err)
return err
}
}
if g := h.Guesses; g != "" {
_, err := tx.Stmt(stmtSaveMeta).Exec(h.ID, "guesses", g)
if err != nil {
elog.Printf("error saving guesses: %s", err)
return err
}
}
return nil return nil
} }

@ -54,13 +54,6 @@ activities are ignored.
Limited support. Limited support.
.It Vt Audio .It Vt Audio
Limited Support. Limited Support.
.It Vt GuessWord
Guess the word game.
(Unofficial extension.)
The solution is stored in
.Fa content
with the possible words, one per line, in a file located at
.Fa wordlist .
.El .El
.Pp .Pp
Honk primarily supports HTML content, not markdown or other formats, Honk primarily supports HTML content, not markdown or other formats,

@ -2,6 +2,22 @@ changelog
=== next === next
+ Remove the wonk support. Fun's over, back to work.
+ All inclusive danger zone spoiler alerts.
+ Emu peeker
+ CSP compliance
+ Filter to match anything with summary/warning.
+ Start collecting quties.
+ Fix http signatures for GET requests.
+ Fix adjacent mentions.
+ Fix argv for chpass. + Fix argv for chpass.
+ Avoid self mention in reply all. + Avoid self mention in reply all.

@ -51,6 +51,7 @@ fields as well.
.It Ar text .It Ar text
Regular expression match against the post Regular expression match against the post
.Fa content . .Fa content .
The special value of "." will match any post with a summary only.
.It Ar is announce .It Ar is announce
Is announced (shared). Is announced (shared).
.It Ar announce of .It Ar announce of

@ -74,7 +74,8 @@ will become a horizontal rule.
.Pp .Pp
If the first line of a honk begins with If the first line of a honk begins with
.Dq DZ: .Dq DZ:
(danger zone) it will be used a summary and the post marked sensitive. (danger zone) or any other combination of two letters and a colon,
it will be used a summary and the post marked sensitive.
.Pp .Pp
Mentioning a specfic user such as Mentioning a specfic user such as
.Pq @user@example.social .Pq @user@example.social
@ -139,6 +140,9 @@ A 24 hour clock is assumed, unless am or pm are specified.
The duration is optional and may be specified as XdYhZm for X days, Y hours, The duration is optional and may be specified as XdYhZm for X days, Y hours,
and Z minutes (1d12h would be a 36 hour event). and Z minutes (1d12h would be a 36 hour event).
.Pp .Pp
Clicking the pretty circle face will open the emu peeker to add in the
selection of emus.
.Pp
When everything is at last ready to go, press the When everything is at last ready to go, press the
.Dq it's gonna be honked .Dq it's gonna be honked
button. button.

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

@ -181,9 +181,6 @@ func reverbolate(userid int64, honks []*Honk) {
h.HTPrecis = template.HTML(h.Precis) h.HTPrecis = template.HTML(h.Precis)
h.HTML = template.HTML(h.Noise) h.HTML = template.HTML(h.Noise)
if h.What == "wonked" {
h.HTML = "? wonk ?"
}
if redo := relingo[h.What]; redo != "" { if redo := relingo[h.What]; redo != "" {
h.What = redo h.What = redo
} }
@ -290,12 +287,14 @@ func imaginate(honk *Honk) {
htf.String(honk.Noise) htf.String(honk.Noise)
} }
var re_dangerous = regexp.MustCompile("^[a-zA-Z]{2}:")
func translate(honk *Honk) { func translate(honk *Honk) {
if honk.Format == "html" { if honk.Format == "html" {
return return
} }
noise := honk.Noise noise := honk.Noise
if strings.HasPrefix(noise, "DZ:") { if re_dangerous.MatchString(noise) {
idx := strings.Index(noise, "\n") idx := strings.Index(noise, "\n")
if idx == -1 { if idx == -1 {
honk.Precis = noise honk.Precis = noise
@ -457,7 +456,7 @@ func memetize(honk *Honk) {
honk.Noise = re_memes.ReplaceAllStringFunc(honk.Noise, repl) honk.Noise = re_memes.ReplaceAllStringFunc(honk.Noise, repl)
} }
var re_quickmention = regexp.MustCompile("(^|[ \n])@[[:alnum:]]+([ \n.]|$)") var re_quickmention = regexp.MustCompile("(^|[ \n])@[[:alnum:]]+([ \n.,']|$)")
func quickrename(s string, userid int64) string { func quickrename(s string, userid int64) string {
nonstop := true nonstop := true
@ -472,7 +471,8 @@ func quickrename(s string, userid int64) string {
prefix += "@" prefix += "@"
m = m[1:] m = m[1:]
tail := "" tail := ""
if last := m[len(m)-1]; last == ' ' || last == '\n' || last == '.' { if last := m[len(m)-1]; last == ' ' || last == '\n' ||
last == '.' || last == ',' || last == '\'' {
tail = m[len(m)-1:] tail = m[len(m)-1:]
m = m[:len(m)-1] m = m[:len(m)-1]
} }
@ -643,7 +643,7 @@ var zaggies = cache.New(cache.Options{Filler: func(keyname string) (httpsig.Publ
data := getxonker(keyname, "pubkey") data := getxonker(keyname, "pubkey")
if data == "" { if data == "" {
dlog.Printf("hitting the webs for missing pubkey: %s", keyname) dlog.Printf("hitting the webs for missing pubkey: %s", keyname)
j, err := GetJunk(serverUID, keyname) j, err := GetJunk(readyLuserOne, keyname)
if err != nil { if err != nil {
ilog.Printf("error getting %s pubkey: %s", keyname, err) ilog.Printf("error getting %s pubkey: %s", keyname, err)
when := time.Now().UTC().Format(dbtimeformat) when := time.Now().UTC().Format(dbtimeformat)

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

@ -25,5 +25,5 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI=
humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M= humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
humungus.tedunangst.com/r/webs v0.6.59 h1:zOlBGZqrRo22QND1CN8HbhEv3JwoiZkspi7TgVuJS0s= humungus.tedunangst.com/r/webs v0.6.60 h1:2PjVTVH3js4PXv8lrEw7nxtRmwwt1COl7t7tZMPxBPs=
humungus.tedunangst.com/r/webs v0.6.59/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc= humungus.tedunangst.com/r/webs v0.6.60/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc=

@ -107,7 +107,7 @@ func filtcachefiller(userid int64) (afiltermap, bool) {
expflush = filt.Expiration expflush = filt.Expiration
} }
} }
if t := filt.Text; t != "" { if t := filt.Text; t != "" && t != "." {
wordfront := t[0] != '#' wordfront := t[0] != '#'
wordtail := true wordtail := true
t = "(?i:" + t + ")" t = "(?i:" + t + ")"
@ -314,7 +314,7 @@ func matchfilterX(h *Honk, f *Filter) string {
rv += " announce" rv += " announce"
} }
} }
if match && f.Text != "" { if match && f.Text != "" && f.Text != "." {
match = false match = false
re := f.re_text re := f.re_text
m := re.FindString(h.Precis) m := re.FindString(h.Precis)
@ -334,6 +334,13 @@ func matchfilterX(h *Honk, f *Filter) string {
rv = m rv = m
} }
} }
if match && f.Text == "." {
match = false
if h.Precis != "" {
match = true
rv = h.Precis
}
}
if match { if match {
return rv return rv
} }

@ -51,16 +51,16 @@ type WhatAbout struct {
} }
type UserOptions struct { type UserOptions struct {
SkinnyCSS bool `json:",omitempty"` SkinnyCSS bool `json:",omitempty"`
OmitImages bool `json:",omitempty"` OmitImages bool `json:",omitempty"`
Avahex bool `json:",omitempty"` MentionAll bool `json:",omitempty"`
MentionAll bool `json:",omitempty"` InlineQuotes bool `json:",omitempty"`
Avatar string `json:",omitempty"` Avatar string `json:",omitempty"`
Banner string `json:",omitempty"` Banner string `json:",omitempty"`
MapLink string `json:",omitempty"` MapLink string `json:",omitempty"`
Reaction string `json:",omitempty"` Reaction string `json:",omitempty"`
MeCount int64 MeCount int64
ChatCount int64 ChatCount int64
} }
type KeyInfo struct { type KeyInfo struct {
@ -69,6 +69,7 @@ type KeyInfo struct {
} }
const serverUID int64 = -2 const serverUID int64 = -2
const readyLuserOne int64 = 1
type Honk struct { type Honk struct {
ID int64 ID int64
@ -103,8 +104,6 @@ type Honk struct {
Time *Time Time *Time
Mentions []Mention Mentions []Mention
Badonks []Badonk Badonks []Badonk
Wonkles string
Guesses template.HTML
} }
type Badonk struct { type Badonk struct {
@ -179,10 +178,6 @@ func (honk *Honk) IsReacted() bool {
return honk.Flags&flagIsReacted != 0 return honk.Flags&flagIsReacted != 0
} }
func (honk *Honk) IsWonked() bool {
return honk.Flags&flagIsWonked != 0
}
type Donk struct { type Donk struct {
FileID int64 FileID int64
XID string XID string

@ -3,12 +3,12 @@
<div class="info"> <div class="info">
{{ .AboutMsg }} {{ .AboutMsg }}
<p> <p>
<table style="font-size:0.8em"> <table class="font08em">
<tbody> <tbody>
<tr><td>version:<td style="text-align:right">{{ .HonkVersion }} <tr><td>version:<td class="textright">{{ .HonkVersion }}
<tr><td>memory:<td style="text-align:right">{{ printf "%.02f" .Sensors.Memory }}MB <tr><td>memory:<td class="textright">{{ printf "%.02f" .Sensors.Memory }}MB
<tr><td>uptime:<td style="text-align:right">{{ printf "%.02f" .Sensors.Uptime }}s <tr><td>uptime:<td class="textright">{{ printf "%.02f" .Sensors.Uptime }}s
<tr><td>cputime:<td style="text-align:right">{{ printf "%.02f" .Sensors.CPU }}s <tr><td>cputime:<td class="textright">{{ printf "%.02f" .Sensors.CPU }}s
</table> </table>
<p> <p>
</div> </div>

@ -10,13 +10,12 @@
<p><textarea name="whatabout">{{ .WhatAbout }}</textarea> <p><textarea name="whatabout">{{ .WhatAbout }}</textarea>
<p><label class="button" for="skinny">skinny layout:</label> <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> <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> <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> <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> <p><label class="button" for="mentionall">mention all:</label>
<input tabindex=1 type="checkbox" id="mentionall" name="mentionall" value="mentionall" {{ if .User.Options.MentionAll }}checked{{ end }}><span></span> <input tabindex=1 type="checkbox" id="mentionall" name="mentionall" value="mentionall" {{ if .User.Options.MentionAll }}checked{{ end }}><span></span>
<p><label class="button" for="inlineqts">inline quotes:</label>
<input tabindex=1 type="checkbox" id="inlineqts" name="inlineqts" value="inlineqts" {{ if .User.Options.InlineQuotes }}checked{{ end }}><span></span>
<p><label class="button" for="maps">apple map links:</label> <p><label class="button" for="maps">apple map links:</label>
<input tabindex=1 type="checkbox" id="maps" name="maps" value="apple" {{ if eq "apple" .User.Options.MapLink }}checked{{ end }}><span></span> <input tabindex=1 type="checkbox" id="maps" name="maps" value="apple" {{ if eq "apple" .User.Options.MapLink }}checked{{ end }}><span></span>
<p><label class="button" for="reaction">reaction:</label> <p><label class="button" for="reaction">reaction:</label>

@ -1,4 +1,5 @@
{{ template "header.html" . }} {{ template "header.html" . }}
<script src="/misc.js{{ .MiscJSParam }}" defer></script>
<main> <main>
<div class="info"> <div class="info">
<p> <p>
@ -10,14 +11,8 @@
<p><label for=noise>noise:</label><br> <p><label for=noise>noise:</label><br>
<textarea name="noise" id="noise"></textarea> <textarea name="noise" id="noise"></textarea>
<p><button name="chonk" value="chonk">chonk</button> <p><button name="chonk" value="chonk">chonk</button>
<label class=button id="donker">attach: <input onchange="updatedonker(this);" type="file" name="donk"><span></span></label> <label class=button id="donker">attach: <input type="file" name="donk"><span></span></label>
</form> </form>
<script>
function updatedonker(el) {
el = el.parentElement
el.children[1].textContent = el.children[0].value.slice(-20)
}
</script>
</div> </div>
{{ $chonkcsrf := .ChonkCSRF }} {{ $chonkcsrf := .ChonkCSRF }}
{{ range .Chatter }} {{ range .Chatter }}
@ -59,7 +54,7 @@ chatter: {{ .Target }}
<p><label for=noise>noise:</label><br> <p><label for=noise>noise:</label><br>
<textarea name="noise" id="noise"></textarea> <textarea name="noise" id="noise"></textarea>
<p><button name="chonk" value="chonk">chonk</button> <p><button name="chonk" value="chonk">chonk</button>
<label class=button id="donker">attach: <input onchange="updatedonker(this);" type="file" name="donk"><span></span></label> <label class=button id="donker">attach: <input type="file" name="donk"><span></span></label>
</form> </form>
</section> </section>
{{ end }} {{ end }}

@ -6,7 +6,7 @@
{{ range .Combos }} {{ range .Combos }}
<section class="honk"> <section class="honk">
<header> <header>
<p style="font-size: 1.8em"><a href="/c/{{ . }}">{{ . }}</a> <p class="font18em"><a href="/c/{{ . }}">{{ . }}</a>
</header> </header>
</section> </section>
{{ end }} {{ end }}

@ -0,0 +1 @@
{{ range .Emus }}<img class="emu" alt=":{{.Name}}:" src="{{ .ID }}">{{ end }}

@ -6,14 +6,11 @@
{{ if .LocalStyleParam }} {{ if .LocalStyleParam }}
<link href="/local.css{{ .LocalStyleParam }}" rel="stylesheet"> <link href="/local.css{{ .LocalStyleParam }}" rel="stylesheet">
{{ end }} {{ end }}
<style>
{{ .UserStyle }}
</style>
<link href="/icon.png" rel="icon"> <link href="/icon.png" rel="icon">
<meta name="theme-color" content="#305"> <meta name="theme-color" content="#305">
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
</head> </head>
<body> <body{{ if .UserStyle}} {{ .UserStyle }}{{ end }}>
<header> <header>
{{ if .UserInfo }} {{ if .UserInfo }}
<details id="topmenu"> <details id="topmenu">
@ -22,7 +19,7 @@
<li><a id="homelink" href="/">home</a> <li><a id="homelink" href="/">home</a>
<li><a id="atmelink" href="/atme">@me<span id=mecount>{{ if .UserInfo.Options.MeCount }}({{ .UserInfo.Options.MeCount }}){{ end }}</span></a> <li><a id="atmelink" href="/atme">@me<span id=mecount>{{ if .UserInfo.Options.MeCount }}({{ .UserInfo.Options.MeCount }}){{ end }}</span></a>
<li><a id="firstlink" href="/first">first</a> <li><a id="firstlink" href="/first">first</a>
<li style="list-style-type:none; margin-left:-1em"> <li class="details">
<details> <details>
<summary>combos</summary> <summary>combos</summary>
<ul> <ul>
@ -39,7 +36,7 @@
<li><a href="/honkers">honkers</a> <li><a href="/honkers">honkers</a>
<li><a href="/hfcs">filters</a> <li><a href="/hfcs">filters</a>
<li><a href="/account">account</a> <li><a href="/account">account</a>
<li style="list-style-type:none; margin-left:-1em"> <li class="details">
<details> <details>
<summary>more stuff</summary> <summary>more stuff</summary>
<ul> <ul>
@ -59,7 +56,7 @@
</details> </details>
<div id="topspacer"> <div id="topspacer">
<p> <p>
<p class="nophone" onclick="window.scrollTo(0,0)">top <p class="nophone">top
</div> </div>
{{ else }} {{ else }}
<div id="topmenu"> <div id="topmenu">

@ -1,4 +1,4 @@
<article class="honk {{ .Honk.Style }}" data-convoy="{{ .Honk.Convoy }}"> <article class="honk {{ .Honk.Style }}" data-convoy="{{ .Honk.Convoy }}" data-hname="{{ .Honk.Handles }}" data-xid="{{ .Honk.XID }}" data-id="{{ .Honk.ID }}">
{{ $bonkcsrf := .BonkCSRF }} {{ $bonkcsrf := .BonkCSRF }}
{{ $IsPreview := .IsPreview }} {{ $IsPreview := .IsPreview }}
{{ $maplink := .MapLink }} {{ $maplink := .MapLink }}
@ -30,7 +30,7 @@
<span class="clip"><a href="{{ .URL }}" rel=noreferrer>{{ .What }}</a> {{ .Date.Local.Format "02 Jan 2006 15:04 -0700" }}</span> <span class="clip"><a href="{{ .URL }}" rel=noreferrer>{{ .What }}</a> {{ .Date.Local.Format "02 Jan 2006 15:04 -0700" }}</span>
{{ if .Oonker }} {{ if .Oonker }}
<br> <br>
<span style="margin-left: 1em;" class="clip"> <span class="left1em clip">
{{ if $bonkcsrf }} {{ if $bonkcsrf }}
original: <a class="honkerlink" href="/h?xid={{ .Oonker }}" data-xid="{{ .Oonker }}">{{ .Oondle }}</a> original: <a class="honkerlink" href="/h?xid={{ .Oonker }}" data-xid="{{ .Oonker }}">{{ .Oondle }}</a>
{{ else }} {{ else }}
@ -40,14 +40,14 @@ original: <a href="{{ .Oonker }}" rel=noreferrer>{{ .Oondle }}</a>
{{ else }} {{ else }}
{{ if .RID }} {{ if .RID }}
<br> <br>
<span style="margin-left: 1em;" class="clip"> <span class="left1em clip">
in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a> in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
</span> </span>
{{ end }} {{ end }}
{{ end }} {{ end }}
<br> <br>
{{ if $bonkcsrf }} {{ if $bonkcsrf }}
<span style="margin-left: 1em;" class="clip">convoy: <a class="convoylink" href="/t?c={{ .Convoy }}">{{ .Convoy }}</a></span> <span class="left1em clip">convoy: <a class="convoylink" href="/t?c={{ .Convoy }}">{{ .Convoy }}</a></span>
{{ end }} {{ end }}
</header> </header>
<p> <p>
@ -89,15 +89,6 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
{{ end }} {{ end }}
</details> </details>
{{ end }} {{ end }}
{{ if eq .Honk.What "wonked" }}
<p>
{{ if and $bonkcsrf .Honk.IsWonked }}
{{ .Honk.Guesses }}
<p>{{ .Honk.Noise }}
{{ else }}
<button onclick="return playit(this, '{{ .Honk.Noise }}', '{{ .Honk.Wonkles }}', '{{ .Honk.XID }}')">it's play time!</button>
{{ end }}
{{ end }}
{{ if and $bonkcsrf (not $IsPreview) }} {{ if and $bonkcsrf (not $IsPreview) }}
<p> <p>
<details class="actions"> <details class="actions">
@ -106,41 +97,41 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
<p> <p>
{{ if .Honk.Public }} {{ if .Honk.Public }}
{{ if .Honk.IsBonked }} {{ if .Honk.IsBonked }}
<button onclick="return unbonk(this, '{{ .Honk.XID }}');">unbonk</button> <button class="unbonk">unbonk</button>
{{ else }} {{ else }}
<button onclick="return bonk(this, '{{ .Honk.XID }}');">bonk</button> <button class="bonk">bonk</button>
{{ end }} {{ end }}
{{ else }} {{ else }}
<button disabled>nope</button> <button disabled>nope</button>
{{ end }} {{ end }}
<button onclick="return showhonkform(this, '{{ .Honk.XID }}', '{{ .Honk.Handles }}');"><a href="/newhonk?rid={{ .Honk.XID }}">honk back</a></button> <button class="honkback"><a href="/newhonk?rid={{ .Honk.XID }}">honk back</a></button>
<button onclick="return muteit(this, '{{ .Honk.Convoy }}');">mute</button> <button class="mute">mute</button>
<button onclick="return showelement('evenmore{{ .Honk.ID }}')">even more</button> <button class="evenmore">even more</button>
</div> </div>
<div id="evenmore{{ .Honk.ID }}" style="display:none"> <div id="evenmore{{ .Honk.ID }}" class="hide">
<p> <p>
<button onclick="return zonkit(this, '{{ .Honk.XID }}');">zonk</button> <button class="zonk">zonk</button>
{{ if .Honk.IsAcked }} {{ if .Honk.IsAcked }}
<button onclick="return flogit(this, 'deack', '{{ .Honk.XID }}');">deack</button> <button class="flogit-deack">deack</button>
{{ else }} {{ else }}
<button onclick="return flogit(this, 'ack', '{{ .Honk.XID }}');">ack</button> <button class="flogit-ack" >ack</button>
{{ end }} {{ end }}
{{ if .Honk.IsSaved }} {{ if .Honk.IsSaved }}
<button onclick="return flogit(this, 'unsave', '{{ .Honk.XID }}');">unsave</button> <button class="flogit-unsave">unsave</button>
{{ else }} {{ else }}
<button onclick="return flogit(this, 'save', '{{ .Honk.XID }}');">save</button> <button class="flogit-save">save</button>
{{ end }} {{ end }}
{{ if .Honk.IsUntagged }} {{ if .Honk.IsUntagged }}
<button disabled>untagged</button> <button disabled>untagged</button>
{{ else }} {{ else }}
<button onclick="return flogit(this, 'untag', '{{ .Honk.XID }}');">untag me</button> <button class="flogit-untag">untag me</button>
{{ end }} {{ end }}
<button><a href="/edit?xid={{ .Honk.XID }}">edit</a></button> <button><a href="/edit?xid={{ .Honk.XID }}">edit</a></button>
{{ if not (eq .Badonk "none") }} {{ if not (eq .Badonk "none") }}
{{ if .Honk.IsReacted }} {{ if .Honk.IsReacted }}
<button disabled>badonked</button> <button disabled>badonked</button>
{{ else }} {{ else }}
<button onclick="return flogit(this, 'react', '{{ .Honk.XID }}');">{{ .Badonk }}</button> <button class="flogit-react" >{{ .Badonk }}</button>
{{ end }} {{ end }}
{{ end }} {{ end }}
</div> </div>

@ -1,4 +1,5 @@
{{ template "header.html" . }} {{ template "header.html" . }}
<script src="/misc.js{{ .MiscJSParam }}" defer></script>
<main> <main>
<div class="info"> <div class="info">
<p> <p>
@ -21,21 +22,13 @@
</div> </div>
{{ $honkercsrf := .HonkerCSRF }} {{ $honkercsrf := .HonkerCSRF }}
<div class="info"> <div class="info">
<script> <p><button class="expand">expand</button>
function expandstuff() {
var els = document.querySelectorAll(".honk details")
for (var i = 0; i < els.length; i++) {
els[i].open = true
}
}
</script>
<p><button onclick="expandstuff()">expand</button>
</div> </div>
{{ range .Honkers }} {{ range .Honkers }}
<section class="honk"> <section class="honk">
<header> <header>
<img alt="avatar" src="/a?a={{ .XID }}" loading="lazy"> <img alt="avatar" src="/a?a={{ .XID }}" loading="lazy">
<p style="font-size: 1.8em"><a href="/h/{{ .Name }}">{{ .Name }}<a> <p class="font18em"><a href="/h/{{ .Name }}">{{ .Name }}</a>
</header> </header>
<p> <p>
<details> <details>

@ -1,6 +1,6 @@
<p id="honkformhost"> <p id="honkformhost">
<button id="honkingtime" onclick="return showhonkform();" {{ if .IsPreview }}style="display:none"{{ end }}><a href="/newhonk">it's honking time</a></button> <button id="honkingtime" {{ if .IsPreview }}class="hide"{{ end }}><a href="/newhonk">it's honking time</a></button>
<form id="honkform" action="/honk" method="POST" enctype="multipart/form-data" {{ if not .IsPreview }}style="display: none"{{ end }}> <form id="honkform" action="/honk" method="POST" enctype="multipart/form-data" {{ if not .IsPreview }}class="hide"{{ end }}>
<input type="hidden" name="CSRF" value="{{ .HonkCSRF }}"> <input type="hidden" name="CSRF" value="{{ .HonkCSRF }}">
<input type="hidden" name="updatexid" id="updatexidinput" value = "{{ .UpdateXID }}"> <input type="hidden" name="updatexid" id="updatexidinput" value = "{{ .UpdateXID }}">
<input type="hidden" name="rid" id="ridinput" value="{{ .InReplyTo }}"> <input type="hidden" name="rid" id="ridinput" value="{{ .InReplyTo }}">
@ -9,12 +9,12 @@
<details> <details>
<summary>more options</summary> <summary>more options</summary>
<p> <p>
<label class=button id="donker">attach: <input onchange="updatedonker();" type="file" name="donk"><span>{{ .SavedFile }}</span></label> <label class=button id="donker">attach: <input type="file" name="donk"><span>{{ .SavedFile }}</span></label>
<input type="hidden" id="saveddonkxid" name="donkxid" value="{{ .SavedFile }}"> <input type="hidden" id="saveddonkxid" name="donkxid" value="{{ .SavedFile }}">
<p id="donkdescriptor"><label for=donkdesc>description:</label><br> <p id="donkdescriptor"><label for=donkdesc>description:</label><br>
<input type="text" name="donkdesc" value="{{ .DonkDesc }}" autocomplete=off> <input type="text" name="donkdesc" value="{{ .DonkDesc }}" autocomplete=off>
{{ with .SavedPlace }} {{ with .SavedPlace }}
<p><button id=checkinbutton type=button onclick="fillcheckin()">checkin</button> <p><button id=checkinbutton type=button>checkin</button>
<div id=placedescriptor> <div id=placedescriptor>
<p><label>name:</label><br><input type="text" name="placename" id=placenameinput value="{{ .Name }}"> <p><label>name:</label><br><input type="text" name="placename" id=placenameinput value="{{ .Name }}">
<p><label>url:</label><br><input type="text" name="placeurl" id=placeurlinput value="{{ .Url }}"> <p><label>url:</label><br><input type="text" name="placeurl" id=placeurlinput value="{{ .Url }}">
@ -22,26 +22,34 @@
<label>lon: </label><input type="text" size=9 name="placelong" id=placelonginput value="{{ .Longitude }}"> <label>lon: </label><input type="text" size=9 name="placelong" id=placelonginput value="{{ .Longitude }}">
</div> </div>
{{ else }} {{ else }}
<p><button id=checkinbutton type=button onclick="fillcheckin()">checkin</button> <p><button id=checkinbutton type=button>checkin</button>
<div id=placedescriptor style="display: none"> <div id=placedescriptor class="hide">
<p><label>name:</label><br><input type="text" name="placename" id=placenameinput value=""> <p><label>name:</label><br><input type="text" name="placename" id=placenameinput value="">
<p><label>url:</label><br><input type="text" name="placeurl" id=placeurlinput value=""> <p><label>url:</label><br><input type="text" name="placeurl" id=placeurlinput value="">
<p><label>lat: </label><input type="text" size=9 name="placelat" id=placelatinput value=""> <p><label>lat: </label><input type="text" size=9 name="placelat" id=placelatinput value="">
<label>lon: </label><input type="text" size=9 name="placelong" id=placelonginput value=""> <label>lon: </label><input type="text" size=9 name="placelong" id=placelonginput value="">
</div> </div>
{{ end }} {{ end }}
<p><button id=addtimebutton type=button onclick="showelement('timedescriptor')">add time</button> <p><button id=addtimebutton type=button>add time</button>
<div id=timedescriptor style="{{ or .ShowTime "display: none" }}"> <div id=timedescriptor class="{{ or .ShowTime "hide" }}">
<p><label for=timestart>start:</label><br> <p><label for=timestart>start:</label><br>
<input type="text" name="timestart" value="{{ .StartTime }}"> <input type="text" name="timestart" value="{{ .StartTime }}">
<p><label for=timeend>duration:</label><br> <p><label for=timeend>duration:</label><br>
<input type="text" name="timeend" value="{{ .Duration }}"> <input type="text" name="timeend" value="{{ .Duration }}">
</div> </div>
<svg class="emuload" id="emuload" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-mood-neutral" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<circle cx="12" cy="12" r="9"></circle>
<line x1="9" y1="10" x2="9.01" y2="10"></line>
<line x1="15" y1="10" x2="15.01" y2="10"></line>
</svg>
<div id="emupicker">
</div>
</details> </details>
<p> <p>
<textarea name="noise" id="honknoise">{{ .Noise }}</textarea> <textarea name="noise" id="honknoise">{{ .Noise }}</textarea>
<p class="buttonarray"> <p class="buttonarray">
<button>it's gonna be honked</button> <button>it's gonna be honked</button>
<button name="preview" value="preview">preview</button> <button name="preview" value="preview">preview</button>
<button type=button name="cancel" value="cancel" onclick="cancelhonking()">cancel</button> <button type=button name="cancel" value="cancel">cancel</button>
</form> </form>

@ -3,42 +3,24 @@
<div class="info" id="infobox"> <div class="info" id="infobox">
<div id="srvmsg"> <div id="srvmsg">
{{ if .Name }} {{ if .Name }}
<p>{{ .Name }} <span style="margin-left:1em;"><a href="/u/{{ .Name }}/rss">rss</a></span> <p>{{ .Name }} <span class="left1em"><a href="/u/{{ .Name }}/rss">rss</a></span>
<p>{{ .WhatAbout }} <p>{{ .WhatAbout }}
{{ end }} {{ end }}
<p>{{ .ServerMessage }} <p>{{ .ServerMessage }}
</div> </div>
{{ if .HonkCSRF }} {{ if .HonkCSRF }}
{{ template "honkform.html" . }} {{ template "honkform.html" . }}
<script> <script src="/honkpage.js{{ .JSParam }}" defer data-csrf="{{ .HonkCSRF }}" data-pagename="{{ .PageName }}" data-pagearg="{{ .PageArg }}" data-tophid="{{ .TopHID }}" data-srvmsg="{{ .ServerMessage }}"></script>
var csrftoken = {{ .HonkCSRF }}
var honksforpage = { }
var curpagestate = { name: "{{ .PageName }}", arg : "{{ .PageArg }}" }
var tophid = { }
tophid[curpagestate.name + ":" + curpagestate.arg] = "{{ .TopHID }}"
var servermsgs = { }
servermsgs[curpagestate.name + ":" + curpagestate.arg] = "{{ .ServerMessage }}"
</script>
<script src="/honkpage.js{{ .JSParam }}"></script>
{{ end }} {{ end }}
<script>
function playit(elem, word, wordlist, xid) {
import('/wonk.js').then(module => {
makeaguess = module.makeaguess
module.addguesscontrols(elem, word, wordlist, xid)
})
}
</script>
{{ if .LocalJSParam }} {{ if .LocalJSParam }}
<script src="/local.js{{ .LocalJSParam }}"></script> <script src="/local.js{{ .LocalJSParam }}" defer></script>
{{ end }} {{ end }}
</div> </div>
{{ if and .HonkCSRF (not .IsPreview) }} {{ if and .HonkCSRF (not .IsPreview) }}
<div class="info" id="refreshbox"> <div class="info" id="refreshbox">
<p><button onclick="refreshhonks(this)">refresh</button><span></span> <p><button class="refresh">refresh</button><span></span>
<button onclick="oldestnewest(this)">scroll down</button> <button class="scrolldown">scroll down</button>
</div> </div>
{{ if eq .ServerMessage "one honk maybe more" }} <script> hideelement("refreshbox")</script> {{ end }}
{{ end }} {{ end }}
<div id="honksonpage"> <div id="honksonpage">
<div> <div>

@ -1,10 +1,16 @@
var csrftoken = ""
var honksforpage = { }
var curpagestate = { name: "", arg : "" }
var tophid = { }
var servermsgs = { }
function encode(hash) { function encode(hash) {
var s = [] var s = []
for (var key in hash) { for (var key in hash) {
var val = hash[key] var val = hash[key]
s.push(escape(key) + "=" + escape(val)) s.push(encodeURIComponent(key) + "=" + encodeURIComponent(val))
} }
return s.join("&") return s.join("&")
} }
function post(url, data) { function post(url, data) {
var x = new XMLHttpRequest() var x = new XMLHttpRequest()
@ -268,25 +274,72 @@ function relinklinks() {
el.onclick = pageswitcher("honker", xid) el.onclick = pageswitcher("honker", xid)
el.classList.remove("honkerlink") el.classList.remove("honkerlink")
} }
els = document.querySelectorAll("#honksonpage article button")
els.forEach(function(el) {
var honk = el.closest("article")
var convoy = honk.dataset.convoy
var hname = honk.dataset.hname
var xid = honk.dataset.xid
var id = Number(honk.dataset.id)
if (!(id > 0)) {
console.error("could not determine honk id")
return
}
if (el.classList.contains("unbonk")) {
el.onclick = function() {
unbonk(el, xid);
}
} else if (el.classList.contains("bonk")) {
el.onclick = function() {
bonk(el, xid)
}
} else if (el.classList.contains("honkback")) {
el.onclick = function() {
return showhonkform(el, xid, hname)
}
} else if (el.classList.contains("mute")) {
el.onclick = function() {
muteit(el, convoy);
}
} else if (el.classList.contains("evenmore")) {
var more = document.querySelector("#evenmore"+id);
el.onclick = function() {
more.classList.toggle("hide");
}
} else if (el.classList.contains("zonk")) {
el.onclick = function() {
zonkit(el, xid);
}
} else if (el.classList.contains("flogit-deack")) {
el.onclick = function() {
flogit(el, "deack", xid);
}
} else if (el.classList.contains("flogit-ack")) {
el.onclick = function() {
flogit(el, "ack", xid);
}
} else if (el.classList.contains("flogit-unsave")) {
el.onclick = function() {
flogit(el, "unsave", xid);
}
} else if (el.classList.contains("flogit-save")) {
el.onclick = function() {
flogit(el, "save", xid);
}
} else if (el.classList.contains("flogit-untag")) {
el.onclick = function() {
flogit(el, "untag", xid);
}
} else if (el.classList.contains("flogit-react")) {
el.onclick = function() {
flogit(el, "react", xid);
}
}
})
} }
(function() {
var el = document.getElementById("homelink")
el.onclick = pageswitcher("home", "")
el = document.getElementById("atmelink")
el.onclick = pageswitcher("atme", "")
el = document.getElementById("firstlink")
el.onclick = pageswitcher("first", "")
el = document.getElementById("savedlink")
el.onclick = pageswitcher("saved", "")
el = document.getElementById("longagolink")
el.onclick = pageswitcher("longago", "")
relinklinks()
window.onpopstate = statechanger
history.replaceState(curpagestate, "some title", "")
})();
(function() {
hideelement("donkdescriptor")
})();
function showhonkform(elem, rid, hname) { function showhonkform(elem, rid, hname) {
var form = lehonkform var form = lehonkform
form.style = "display: block" form.style = "display: block"
@ -363,3 +416,92 @@ function fillcheckin() {
}, gpsoptions) }, gpsoptions)
} }
} }
function addemu(elem) {
const data = elem.alt
const box = document.getElementById("honknoise");
box.value += data;
}
function loademus() {
div = document.getElementById("emupicker")
request = new XMLHttpRequest()
request.open('GET', '/emus')
request.onload = function() {
div.innerHTML = request.responseText
div.querySelectorAll(".emu").forEach(function(el) {
el.onclick = function() {
addemu(el)
}
})
}
if (div.style.display === "none") {
div.style.display = "block";
} else {
div.style.display = "none";
}
request.send()
}
// init
(function() {
var me = document.currentScript;
csrftoken = me.dataset.csrf
curpagestate.name = me.dataset.pagename
curpagestate.arg = me.dataset.pagearg
tophid[curpagestate.name + ":" + curpagestate.arg] = me.dataset.tophid
servermsgs[curpagestate.name + ":" + curpagestate.arg] = me.dataset.srvmsg
var el = document.getElementById("homelink")
el.onclick = pageswitcher("home", "")
el = document.getElementById("atmelink")
el.onclick = pageswitcher("atme", "")
el = document.getElementById("firstlink")
el.onclick = pageswitcher("first", "")
el = document.getElementById("savedlink")
el.onclick = pageswitcher("saved", "")
el = document.getElementById("longagolink")
el.onclick = pageswitcher("longago", "")
var totop = document.querySelector(".nophone")
if (totop) {
totop.onclick = function() {
window.scrollTo(0,0)
}
}
var refreshbox = document.getElementById("refreshbox")
if (refreshbox) {
refreshbox.querySelectorAll("button").forEach(function(el) {
if (el.classList.contains("refresh")) {
el.onclick = function() {
refreshhonks(el)
}
} else if (el.classList.contains("scrolldown")) {
el.onclick = function() {
oldestnewest(el)
}
}
})
if (me.dataset.srvmsg == "one honk maybe more") {
hideelement(refreshbox)
}
}
var td = document.getElementById("timedescriptor")
document.getElementById("addtimebutton").onclick = function() {
td.classList.toggle("hide")
}
document.getElementById("honkingtime").onclick = function() {
return showhonkform()
}
document.getElementById("checkinbutton").onclick = fillcheckin
document.getElementById("emuload").onclick = loademus
document.querySelector("#donker input").onchange = updatedonker
document.querySelector("button[name=cancel]").onclick = cancelhonking
relinklinks()
window.onpopstate = statechanger
history.replaceState(curpagestate, "some title", "")
hideelement("donkdescriptor")
})();

@ -0,0 +1,25 @@
function expandstuff() {
var els = document.querySelectorAll(".honk details")
for (var i = 0; i < els.length; i++) {
els[i].open = true
}
}
function updatedonker(el) {
el = el.parentElement
el.children[1].textContent = el.children[0].value.slice(-20)
}
(function() {
var expand = document.querySelector("button.expand")
if (expand) {
expand.onclick = expandstuff
}
var donk = document.querySelector("#donker input")
if (donk) {
donk.onchange = function() {
updatedonker(this);
}
}
})()

@ -10,7 +10,7 @@
{{ $letter = (call $firstrune .Name) }} {{ $letter = (call $firstrune .Name) }}
<li><p> <li><p>
{{ end }} {{ end }}
<span style="white-space: nowrap;"><a href="/o/{{ .Name }}">#{{ .Name }}</a> ({{ .Count }})</span> <span class="wsnowrap"><a href="/o/{{ .Name }}">#{{ .Name }}</a> ({{ .Count }})</span>
{{ end }} {{ end }}
</ul> </ul>
</div> </div>

@ -253,6 +253,11 @@ input[type=file] {
.honk details.actions summary { .honk details.actions summary {
color: var(--fg-subtle); color: var(--fg-subtle);
} }
#emupicker{height:300px;overflow-y:scroll;padding:3px;background:var(--bg-dark);border:solid 5px var(--fg-subtle);text-align:center;display:none;}
#emupicker img{margin:0;}
.emuload{background:var(--bg-page);padding:0.5em;}
.subtle .noise { .subtle .noise {
color: var(--fg-subtle); color: var(--fg-subtle);
font-size: 0.8em; font-size: 0.8em;
@ -340,3 +345,44 @@ img.emu {
--fg-limited: #a79; --fg-limited: #a79;
} }
} }
/*
* CSP: style-src: self
*/
li.details {
list-style-type: none;
margin-left: -1em;
}
.left1em {
margin-left: 1em;
}
.hide {
display: none;
}
.textright {
text-align: right;
}
.font08em {
font-size: 0.8em;
}
.font18em {
font-size: 1.8em;
}
.wsnowrap {
white-space: nowrap;
}
.skinny main {
max-width: 700px;
}
.fontmonospace {
font-family: monospace;
}

@ -1,83 +0,0 @@
export function addguesscontrols(elem, word, wordlist, xid) {
var host = elem.parentElement
elem.innerHTML = "loading..."
host.correctAnswer = word
host.guesses = []
host.xid = xid
var xhr = new XMLHttpRequest()
xhr.open("GET", "/bloat/wonkles?w=" + escape(wordlist))
xhr.responseType = "json"
xhr.onload = function() {
var wordlist = xhr.response.wordlist
var validguesses = {}
console.log("valid " + wordlist.length)
for (var i = 0; i < wordlist.length; i++) {
validguesses[wordlist[i]] = true
}
host.validGuesses = validguesses
var div = document.createElement( 'div' );
div.innerHTML = "<p><input> <button onclick='return makeaguess(this)'>guess</button>"
host.append(div)
elem.remove()
}
xhr.send()
}
export function makeaguess(btn) {
var host = btn.parentElement.parentElement.parentElement
var correct = host.correctAnswer
var valid = host.validGuesses
var inp = btn.previousElementSibling
var g = inp.value.toLowerCase()
var res = ""
if (valid[g]) {
var letters = {}
var obfu = ""
for (var i = 0; i < correct.length; i++) {
var l = correct[i]
letters[l] = (letters[l] | 0) + 1
}
for (var i = 0; i < g.length && i < correct.length; i++) {
if (g[i] == correct[i]) {
letters[g[i]] = letters[g[i]] - 1
}
}
for (var i = 0; i < g.length; i++) {
if (i < correct.length && g[i] == correct[i]) {
res += g[i].toUpperCase()
obfu += "&#129001;"
} else if (letters[g[i]] > 0) {
res += g[i]
obfu += "&#129000;"
letters[g[i]] = letters[g[i]] - 1
} else {
obfu += "&#11035;"
res += "."
}
}
var div = document.createElement( 'div' );
div.innerHTML = "<p style='font-family: monospace'>" + res
host.append(div)
host.guesses.push(obfu)
} else {
var div = document.createElement( 'div' );
div.innerHTML = "<p> invalid guess"
host.append(div)
}
var div = document.createElement( 'div' );
if (res == correct.toUpperCase()) {
var mess = "<p>you are very smart!"
mess += "<p>" + host.xid
for (var i = 0; i < host.guesses.length; i++) {
mess += "<p>" + host.guesses[i]
}
div.innerHTML = mess
if (typeof(csrftoken) != "undefined")
post("/zonkit", encode({"CSRF": csrftoken, "wherefore": "wonk", "guesses": host.guesses.join("<p>"), "what": host.xid}))
} else {
div.innerHTML = "<p><input> <button onclick='return makeaguess(this)'>guess</button>"
}
host.append(div)
btn.parentElement.remove()
}

@ -50,16 +50,18 @@ var honkSep = "h"
var develMode = false var develMode = false
func getuserstyle(u *login.UserInfo) template.CSS { var allemus []Emu
func getuserstyle(u *login.UserInfo) template.HTMLAttr {
if u == nil { if u == nil {
return "" return ""
} }
user, _ := butwhatabout(u.Username) user, _ := butwhatabout(u.Username)
css := template.CSS("") class := template.HTMLAttr("")
if user.Options.SkinnyCSS { if user.Options.SkinnyCSS {
css += "main { max-width: 700px; }\n" class += `class="skinny"`
} }
return css return class
} }
func getmaplink(u *login.UserInfo) string { func getmaplink(u *login.UserInfo) string {
@ -80,6 +82,7 @@ func getInfo(r *http.Request) map[string]interface{} {
templinfo["LocalStyleParam"] = getassetparam(dataDir + "/views/local.css") templinfo["LocalStyleParam"] = getassetparam(dataDir + "/views/local.css")
templinfo["JSParam"] = getassetparam(viewDir + "/views/honkpage.js") templinfo["JSParam"] = getassetparam(viewDir + "/views/honkpage.js")
templinfo["LocalJSParam"] = getassetparam(dataDir + "/views/local.js") templinfo["LocalJSParam"] = getassetparam(dataDir + "/views/local.js")
templinfo["MiscJSParam"] = getassetparam(dataDir + "/views/misc.js")
templinfo["ServerName"] = serverName templinfo["ServerName"] = serverName
templinfo["IconName"] = iconName templinfo["IconName"] = iconName
templinfo["UserSep"] = userSep templinfo["UserSep"] = userSep
@ -118,6 +121,7 @@ func homepage(w http.ResponseWriter, r *http.Request) {
honks = gethonksforme(userid, 0) honks = gethonksforme(userid, 0)
honks = osmosis(honks, userid, false) honks = osmosis(honks, userid, false)
menewnone(userid) menewnone(userid)
templinfo["UserInfo"], _ = butwhatabout(u.Username)
case "/longago": case "/longago":
templinfo["ServerMessage"] = "long ago and far away!" templinfo["ServerMessage"] = "long ago and far away!"
templinfo["PageName"] = "longago" templinfo["PageName"] = "longago"
@ -147,6 +151,15 @@ func homepage(w http.ResponseWriter, r *http.Request) {
honkpage(w, u, honks, templinfo) honkpage(w, u, honks, templinfo)
} }
func showemus(w http.ResponseWriter, r *http.Request) {
templinfo := getInfo(r)
templinfo["Emus"] = allemus
err := readviews.Execute(w, "emus.html", templinfo)
if err != nil {
elog.Print(err)
}
}
func showfunzone(w http.ResponseWriter, r *http.Request) { func showfunzone(w http.ResponseWriter, r *http.Request) {
var emunames, memenames []string var emunames, memenames []string
emuext := make(map[string]string) emuext := make(map[string]string)
@ -1111,11 +1124,6 @@ func saveuser(w http.ResponseWriter, r *http.Request) {
} else { } else {
options.SkinnyCSS = false options.SkinnyCSS = false
} }
if r.FormValue("avahex") == "avahex" {
options.Avahex = true
} else {
options.Avahex = false
}
if r.FormValue("omitimages") == "omitimages" { if r.FormValue("omitimages") == "omitimages" {
options.OmitImages = true options.OmitImages = true
} else { } else {
@ -1126,6 +1134,11 @@ func saveuser(w http.ResponseWriter, r *http.Request) {
} else { } else {
options.MentionAll = false options.MentionAll = false
} }
if r.FormValue("inlineqts") == "inlineqts" {
options.InlineQuotes = true
} else {
options.InlineQuotes = false
}
if r.FormValue("maps") == "apple" { if r.FormValue("maps") == "apple" {
options.MapLink = "apple" options.MapLink = "apple"
} else { } else {
@ -1317,21 +1330,6 @@ func zonkit(w http.ResponseWriter, r *http.Request) {
return return
} }
if wherefore == "wonk" {
xonk := getxonk(userinfo.UserID, what)
if xonk != nil {
_, err := stmtUpdateFlags.Exec(flagIsWonked, xonk.ID)
if err == nil {
guesses := r.FormValue("guesses")
_, err = stmtSaveMeta.Exec(xonk.ID, "guesses", guesses)
}
if err != nil {
elog.Printf("error saving: %s", err)
}
}
return
}
// my hammer is too big, oh well // my hammer is too big, oh well
defer oldjonks.Flush() defer oldjonks.Flush()
@ -1433,7 +1431,7 @@ func edithonkpage(w http.ResponseWriter, r *http.Request) {
templinfo["Noise"] = noise templinfo["Noise"] = noise
templinfo["SavedPlace"] = honk.Place templinfo["SavedPlace"] = honk.Place
if tm := honk.Time; tm != nil { if tm := honk.Time; tm != nil {
templinfo["ShowTime"] = ";" templinfo["ShowTime"] = " "
templinfo["StartTime"] = tm.StartTime.Format("2006-01-02 15:04") templinfo["StartTime"] = tm.StartTime.Format("2006-01-02 15:04")
if tm.Duration != 0 { if tm.Duration != 0 {
templinfo["Duration"] = tm.Duration templinfo["Duration"] = tm.Duration
@ -1607,10 +1605,6 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
if rid != "" { if rid != "" {
what = "tonk" what = "tonk"
} }
wonkles := r.FormValue("wonkles")
if wonkles != "" {
what = "wonk"
}
honk = &Honk{ honk = &Honk{
UserID: userinfo.UserID, UserID: userinfo.UserID,
Username: userinfo.Username, Username: userinfo.Username,
@ -1619,7 +1613,6 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
XID: xid, XID: xid,
Date: dt, Date: dt,
Format: format, Format: format,
Wonkles: wonkles,
} }
} }
@ -1649,7 +1642,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
honk.RID = rid honk.RID = rid
if xonk.Precis != "" && honk.Precis == "" { if xonk.Precis != "" && honk.Precis == "" {
honk.Precis = xonk.Precis honk.Precis = xonk.Precis
if !(strings.HasPrefix(honk.Precis, "DZ:") || strings.HasPrefix(honk.Precis, "re: re: re: ")) { if !re_dangerous.MatchString(honk.Precis) {
honk.Precis = "re: " + honk.Precis honk.Precis = "re: " + honk.Precis
} }
} }
@ -1755,7 +1748,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
templinfo["Noise"] = r.FormValue("noise") templinfo["Noise"] = r.FormValue("noise")
templinfo["SavedFile"] = donkxid templinfo["SavedFile"] = donkxid
if tm := honk.Time; tm != nil { if tm := honk.Time; tm != nil {
templinfo["ShowTime"] = ";" templinfo["ShowTime"] = " "
templinfo["StartTime"] = tm.StartTime.Format("2006-01-02 15:04") templinfo["StartTime"] = tm.StartTime.Format("2006-01-02 15:04")
if tm.Duration != 0 { if tm.Duration != 0 {
templinfo["Duration"] = tm.Duration templinfo["Duration"] = tm.Duration
@ -2151,8 +2144,7 @@ func avatate(w http.ResponseWriter, r *http.Request) {
loadAvatarColors() loadAvatarColors()
} }
n := r.FormValue("a") n := r.FormValue("a")
hex := r.FormValue("hex") == "1" a := genAvatar(n)
a := genAvatar(n, hex)
if !develMode { if !develMode {
w.Header().Set("Cache-Control", "max-age="+somedays()) w.Header().Set("Cache-Control", "max-age="+somedays())
} }
@ -2462,6 +2454,37 @@ func bgmonitor() {
} }
} }
func addcspheaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy", "default-src 'none'; script-src 'self'; connect-src 'self'; style-src 'self'; img-src 'self'; report-uri /csp-violation")
next.ServeHTTP(w, r)
})
}
func emuinit() {
var emunames []string
dir, err := os.Open(dataDir + "/emus")
if err == nil {
emunames, _ = dir.Readdirnames(0)
dir.Close()
}
for _, e := range emunames {
if len(e) <= 4 {
continue
}
ext := e[len(e)-4:]
emu := Emu{
ID: fmt.Sprintf("/emu/%s", e),
Name: e[:len(e)-4],
Type: "image/" + ext[1:],
}
allemus = append(allemus, emu)
}
sort.Slice(allemus, func(i, j int) bool {
return allemus[i].Name < allemus[j].Name
})
}
func serve() { func serve() {
db := opendatabase() db := opendatabase()
login.Init(login.InitArgs{Db: db, Logger: ilog, Insecure: develMode, SameSiteStrict: !develMode}) login.Init(login.InitArgs{Db: db, Logger: ilog, Insecure: develMode, SameSiteStrict: !develMode})
@ -2476,6 +2499,7 @@ func serve() {
go tracker() go tracker()
go bgmonitor() go bgmonitor()
loadLingo() loadLingo()
emuinit()
readviews = templates.Load(develMode, readviews = templates.Load(develMode,
viewDir+"/views/honkpage.html", viewDir+"/views/honkpage.html",
@ -2494,6 +2518,7 @@ func serve() {
viewDir+"/views/msg.html", viewDir+"/views/msg.html",
viewDir+"/views/header.html", viewDir+"/views/header.html",
viewDir+"/views/onts.html", viewDir+"/views/onts.html",
viewDir+"/views/emus.html",
viewDir+"/views/honkpage.js", viewDir+"/views/honkpage.js",
) )
if !develMode { if !develMode {
@ -2514,6 +2539,7 @@ func serve() {
} }
mux := mux.NewRouter() mux := mux.NewRouter()
mux.Use(addcspheaders)
mux.Use(login.Checker) mux.Use(login.Checker)
mux.Handle("/api", login.TokenRequired(http.HandlerFunc(apihandler))) mux.Handle("/api", login.TokenRequired(http.HandlerFunc(apihandler)))
@ -2552,7 +2578,7 @@ func serve() {
getters.HandleFunc("/style.css", serveviewasset) getters.HandleFunc("/style.css", serveviewasset)
getters.HandleFunc("/honkpage.js", serveviewasset) getters.HandleFunc("/honkpage.js", serveviewasset)
getters.HandleFunc("/wonk.js", serveviewasset) getters.HandleFunc("/misc.js", serveviewasset)
getters.HandleFunc("/local.css", servedataasset) getters.HandleFunc("/local.css", servedataasset)
getters.HandleFunc("/local.js", servedataasset) getters.HandleFunc("/local.js", servedataasset)
getters.HandleFunc("/icon.png", servedataasset) getters.HandleFunc("/icon.png", servedataasset)
@ -2564,8 +2590,6 @@ func serve() {
getters.HandleFunc("/logout", login.LogoutFunc) getters.HandleFunc("/logout", login.LogoutFunc)
getters.HandleFunc("/help/{name:[\\pL[:digit:]_.-]+}", servehelp) getters.HandleFunc("/help/{name:[\\pL[:digit:]_.-]+}", servehelp)
getters.HandleFunc("/bloat/wonkles", servewonkles)
loggedin := mux.NewRoute().Subrouter() loggedin := mux.NewRoute().Subrouter()
loggedin.Use(login.Required) loggedin.Use(login.Required)
loggedin.HandleFunc("/first", homepage) loggedin.HandleFunc("/first", homepage)
@ -2595,6 +2619,7 @@ func serve() {
loggedin.HandleFunc("/t", showconvoy) loggedin.HandleFunc("/t", showconvoy)
loggedin.HandleFunc("/q", showsearch) loggedin.HandleFunc("/q", showsearch)
loggedin.HandleFunc("/hydra", webhydra) loggedin.HandleFunc("/hydra", webhydra)
loggedin.HandleFunc("/emus", showemus)
loggedin.Handle("/submithonker", login.CSRFWrap("submithonker", http.HandlerFunc(submithonker))) loggedin.Handle("/submithonker", login.CSRFWrap("submithonker", http.HandlerFunc(submithonker)))
err = http.Serve(listener, mux) err = http.Serve(listener, mux)

Loading…
Cancel
Save