Compare commits

..

No commits in common. "10bca44dc51f729d5c4579d03b886974fb43ee69" and "50524cade2d1236e4be684993f0bfd470b240452" have entirely different histories.

26 changed files with 467 additions and 336 deletions

View file

@ -36,5 +36,3 @@ dac64bc6a93cedeb6ae618cba8f8647af96d2ece v0.9.3
6a522536238fe25b6d048543f52ed406ccf720b2 v0.9.6
bc1bcfb9c0cc86b3c63325b07e13a36b9d4500f0 v0.9.7
916cefdc24363b6e7e193dbde82632c17f58adfd v0.9.8
4b8cf31560b7d1e1696af109b158766c4ce823ab v0.9.9
d7c3a01e7aaef67c40920bbc4e8507350fc33e31 v0.9.91

View file

@ -511,8 +511,7 @@ var re_mast0link = regexp.MustCompile(`https://[[:alnum:].]+/users/[[:alnum:]]+/
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_r0malink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
var re_roma1ink = regexp.MustCompile(`https://[[:alnum:].]+/notice/[[:alnum:]]+`)
var re_romalink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
var re_qtlinks = regexp.MustCompile(`>https://[^\s<]+<`)
func qutify(user *WhatAbout, content string) string {
@ -522,11 +521,14 @@ func qutify(user *WhatAbout, content string) string {
mlinks := re_qtlinks.FindAllString(malcontent, -1)
for _, m := range mlinks {
m = m[1 : len(m)-1]
if re_mast0link.MatchString(m) || re_masto1ink.MatchString(m) ||
dlog.Printf("consider qt: %s", m)
if re_mast0link.MatchString(m) ||
re_masto1ink.MatchString(m) ||
re_misslink.MatchString(m) ||
re_honklink.MatchString(m) ||
re_r0malink.MatchString(m) || re_roma1ink.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 {
@ -574,7 +576,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
var replies []string
var obj junk.Junk
waspage := false
preferorig := false
switch what {
case "Delete":
obj, ok = item.GetMap("object")
@ -686,10 +687,11 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
case "Page":
waspage = true
fallthrough
case "GuessWord": // dealt with below
fallthrough
case "Audio":
fallthrough
case "Image":
preferorig = true
fallthrough
case "Video":
fallthrough
@ -818,6 +820,12 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
targ, _ := obj.GetString("target")
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 != "" {
what = "tonk"
}
@ -838,9 +846,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
at, _ := att.GetString("type")
mt, _ := att.GetString("mediaType")
u, ok := att.GetString("url")
if !ok {
u, ok = att.GetString("href")
}
if !ok {
if ua, ok := att.GetArray("url"); ok && len(ua) > 0 {
u, ok = ua[0].(string)
@ -868,7 +873,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
localize := false
if numatts > 4 {
ilog.Printf("excessive attachment: %s", at)
} else if at == "Document" || at == "Image" || (preferorig && at == "Link") {
} else if at == "Document" || at == "Image" {
mt = strings.ToLower(mt)
dlog.Printf("attachment: %s %s", mt, u)
if mt == "text/plain" || mt == "application/pdf" ||
@ -881,30 +886,12 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
if skipMedia(&xonk) {
localize = false
}
if preferorig && !localize {
return
}
donk := savedonk(u, name, desc, mt, localize)
if donk != nil {
xonk.Donks = append(xonk.Donks, donk)
}
numatts++
}
if preferorig {
atts, _ := obj.GetArray("url")
for _, atti := range atts {
att, ok := atti.(junk.Junk)
if !ok {
ilog.Printf("attachment that wasn't map?")
continue
}
procatt(att)
}
if numatts == 0 {
preferorig = false
}
}
if !preferorig {
atts, _ := obj.GetArray("attachment")
for _, atti := range atts {
att, ok := atti.(junk.Junk)
@ -917,7 +904,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
if att, ok := obj.GetMap("attachment"); ok {
procatt(att)
}
}
tags, _ := obj.GetArray("tag")
for _, tagi := range tags {
tag, ok := tagi.(junk.Junk)
@ -1195,6 +1181,8 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
fallthrough
case "event":
fallthrough
case "wonk":
fallthrough
case "honk":
j["type"] = "Create"
jo = junk.New()
@ -1202,6 +1190,8 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
jo["type"] = "Note"
if h.What == "event" {
jo["type"] = "Event"
} else if h.What == "wonk" {
jo["type"] = "GuessWord"
}
if h.What == "update" {
j["type"] = "Update"
@ -1308,11 +1298,14 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
jo["duration"] = "PT" + strings.ToUpper(t.Duration.String())
}
}
if w := h.Wonkles; w != "" {
jo["wordlist"] = w
}
atts := activatedonks(h.Donks)
if len(atts) > 0 {
jo["attachment"] = atts
}
jo["summary"] = h.Precis
jo["summary"] = html.EscapeString(h.Precis)
jo["content"] = h.Noise
j["object"] = jo
case "bonk":
@ -1906,7 +1899,7 @@ func unfollowme(user *WhatAbout, who string, name string, j junk.Junk) {
}
}
func followyou(user *WhatAbout, honkerid int64, sync bool) {
func followyou(user *WhatAbout, honkerid int64) {
var url, owner string
db := opendatabase()
row := db.QueryRow("select xid, owner from honkers where honkerid = ? and userid = ? and flavor in ('unsub', 'peep', 'presub', 'sub')",
@ -1923,37 +1916,26 @@ func followyou(user *WhatAbout, honkerid int64, sync bool) {
elog.Printf("error updating honker: %s", err)
return
}
if sync {
subsub(user, url, owner, folxid)
} else {
go subsub(user, url, owner, folxid)
}
}
func unfollowyou(user *WhatAbout, honkerid int64, sync bool) {
func unfollowyou(user *WhatAbout, honkerid int64) {
db := opendatabase()
row := db.QueryRow("select xid, owner, folxid, flavor from honkers where honkerid = ? and userid = ? and flavor in ('unsub', 'peep', 'presub', 'sub')",
row := db.QueryRow("select xid, owner, folxid from honkers where honkerid = ? and userid = ? and flavor in ('sub')",
honkerid, user.ID)
var url, owner, folxid, flavor string
err := row.Scan(&url, &owner, &folxid, &flavor)
var url, owner, folxid string
err := row.Scan(&url, &owner, &folxid)
if err != nil {
elog.Printf("can't get honker xid: %s", err)
return
}
if flavor == "peep" {
return
}
ilog.Printf("unsubscribing from %s", url)
_, err = db.Exec("update honkers set flavor = ? where honkerid = ?", "unsub", honkerid)
if err != nil {
elog.Printf("error updating honker: %s", err)
return
}
if sync {
itakeitallback(user, url, owner, folxid)
} else {
go itakeitallback(user, url, owner, folxid)
}
}
func followyou2(user *WhatAbout, j junk.Junk) {

View file

@ -14,3 +14,54 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
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
}

View file

@ -485,7 +485,9 @@ func donksforhonks(honks []*Honk) {
continue
}
case "wonkles":
h.Wonkles = j
case "guesses":
h.Guesses = template.HTML(j)
case "oldrev":
default:
elog.Printf("unknown meta genus: %s", genus)
@ -574,20 +576,6 @@ func savefileandxid(name string, desc string, url string, media string, local bo
return fileid, xid, nil
}
func finddonkid(fileid int64, url string) *Donk {
donk := new(Donk)
row := stmtFindFileId.QueryRow(fileid, url)
err := row.Scan(&donk.XID, &donk.Local, &donk.Desc)
if err == nil {
donk.FileID = fileid
return donk
}
if err != sql.ErrNoRows {
elog.Printf("error finding file: %s", err)
}
return nil
}
func finddonk(url string) *Donk {
donk := new(Donk)
row := stmtFindFile.QueryRow(url)
@ -909,6 +897,20 @@ func saveextras(tx *sql.Tx, h *Honk) error {
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
}
@ -976,7 +978,7 @@ func savexonker(what, value, flav, when string) {
stmtSaveXonker.Exec(what, value, flav, when)
}
func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) (int64, error) {
func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) error {
var owner string
if url[0] == '#' {
flavor = "peep"
@ -988,7 +990,7 @@ func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) (int64, e
info, err := investigate(url)
if err != nil {
ilog.Printf("failed to investigate honker: %s", err)
return 0, err
return err
}
url = info.XID
if name == "" {
@ -1007,16 +1009,19 @@ func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) (int64, e
} else {
err = fmt.Errorf("it seems you are already subscribed to them")
}
return 0, err
return err
}
res, err := stmtSaveHonker.Exec(user.ID, name, url, flavor, combos, owner, mj)
if err != nil {
elog.Print(err)
return 0, err
return err
}
honkerid, _ := res.LastInsertId()
return honkerid, nil
if flavor == "presub" {
followyou(user, honkerid)
}
return nil
}
func cleanupdb(arg string) {
@ -1093,7 +1098,7 @@ var stmtHonksByOntology, stmtHonksForUser, stmtHonksForMe, stmtSaveDub, stmtHonk
var stmtHonksFromLongAgo *sql.Stmt
var stmtHonksByHonker, stmtSaveHonk, stmtUserByName, stmtUserByNumber *sql.Stmt
var stmtEventHonks, stmtOneBonk, stmtFindZonk, stmtFindXonk, stmtSaveDonk *sql.Stmt
var stmtFindFile, stmtFindFileId, stmtGetFileData, stmtSaveFileData, stmtSaveFile *sql.Stmt
var stmtFindFile, stmtGetFileData, stmtSaveFileData, stmtSaveFile *sql.Stmt
var stmtCheckFileData *sql.Stmt
var stmtAddDoover, stmtGetDoovers, stmtLoadDoover, stmtZapDoover, stmtOneHonker *sql.Stmt
var stmtUntagged, stmtDeleteHonk, stmtDeleteDonks, stmtDeleteOnts, stmtSaveZonker *sql.Stmt
@ -1163,7 +1168,6 @@ func prepareStatements(db *sql.DB) {
stmtGetFileData = preparetodie(blobdb, "select media, content from filedata where xid = ?")
stmtFindXonk = preparetodie(db, "select honkid from honks where userid = ? and xid = ?")
stmtFindFile = preparetodie(db, "select fileid, xid from filemeta where url = ? and local = 1")
stmtFindFileId = preparetodie(db, "select xid, local, description from filemeta where fileid = ? and url = ? and local = 1")
stmtUserByName = preparetodie(db, "select userid, username, displayname, about, pubkey, seckey, options from users where username = ? and userid > 0")
stmtUserByNumber = preparetodie(db, "select userid, username, displayname, about, pubkey, seckey, options from users where userid = ?")
stmtSaveDub = preparetodie(db, "insert into honkers (userid, name, xid, flavor, combos, owner, meta, folxid) values (?, ?, ?, ?, '', '', '', ?)")

View file

@ -54,6 +54,13 @@ activities are ignored.
Limited support.
.It Vt Audio
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
.Pp
Honk primarily supports HTML content, not markdown or other formats,

View file

@ -1,18 +1,6 @@
changelog
=== 0.9.91 One More Time
+ Swallow a follow bug.
=== 0.9.9 Eat the Bugs
+ Some fixes for image descriptions.
+ Fix double htmlization of subject lines.
+ Remove the wonk support. Fun's over, back to work.
+ All inclusive danger zone spoiler alerts.
=== next
+ Emu peeker

View file

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

View file

@ -158,27 +158,6 @@ Delete this honk.
Mute this thread.
What should identify a convoy.
.El
.Ss gethonkers
Returns a list of current honkers in json format.
.Ss savehonker
Save a new honker, or update an existing one.
The following fields are used.
.Bl -tag -width honkerid
.It Fa honkerid
The numeric ID of an existing honker to update.
.It Fa name
The preferred short name.
.It Fa url
The ActivityPub actor url.
.It Fa combos
Space separated list of combos.
.It Fa notes
Some notes.
.El
.Pp
The honker numeric ID will be returned for success.
To delete, unsub, or sub, include a form value with name and value equal.
As in, a form value named delete with the value delete, or unsub=unsub, etc.
.Ss sendactivity
Send anything.
No limits, no error checking.

View file

@ -74,8 +74,7 @@ will become a horizontal rule.
.Pp
If the first line of a honk begins with
.Dq DZ:
(danger zone) or any other combination of two letters and a colon,
it will be used a summary and the post marked sensitive.
(danger zone) it will be used a summary and the post marked sensitive.
.Pp
Mentioning a specfic user such as
.Pq @user@example.social
@ -122,7 +121,7 @@ A description, or caption, is encouraged.
Text files and PDFs are also supported as attachments.
Other formats are not supported.
.Pp
One may also live dangerously by posting assassination coordinates.
One may also check in to a location.
The available fields, all optional, are
.Ar name ,
.Ar url ,

View file

@ -142,11 +142,6 @@ command.
Users may be deleted with the
.Ic deluser Ar username
command.
.Pp
Follow and unfollow requests can be sent via command line with
.Ic follow Ar username Ar url
and
.Ic unfollow Ar username Ar url .
.Ss Maintenance
The database may grow large over time.
The

24
fun.go
View file

@ -181,6 +181,9 @@ func reverbolate(userid int64, honks []*Honk) {
h.HTPrecis = template.HTML(h.Precis)
h.HTML = template.HTML(h.Noise)
if h.What == "wonked" {
h.HTML = "? wonk ?"
}
if redo := relingo[h.What]; redo != "" {
h.What = redo
}
@ -287,11 +290,12 @@ func imaginate(honk *Honk) {
htf.String(honk.Noise)
}
var re_dangerous = regexp.MustCompile("^[a-zA-Z]{2}:")
func precipitate(honk *Honk) {
func translate(honk *Honk) {
if honk.Format == "html" {
return
}
noise := honk.Noise
if re_dangerous.MatchString(noise) {
if strings.HasPrefix(noise, "DZ:") {
idx := strings.Index(noise, "\n")
if idx == -1 {
honk.Precis = noise
@ -300,16 +304,8 @@ func precipitate(honk *Honk) {
honk.Precis = noise[:idx]
noise = noise[idx+1:]
}
}
honk.Precis = markitzero(strings.TrimSpace(honk.Precis))
honk.Noise = noise
}
}
func translate(honk *Honk) {
if honk.Format == "html" {
return
}
noise := honk.Noise
var marker mz.Marker
marker.HashLinker = ontoreplacer
@ -425,8 +421,6 @@ func herdofemus(noise string) []Emu {
var re_memes = regexp.MustCompile("meme: ?([^\n]+)")
var re_avatar = regexp.MustCompile("avatar: ?([^\n]+)")
var re_banner = regexp.MustCompile("banner: ?([^\n]+)")
var re_convoy = regexp.MustCompile("convoy: ?([^\n]+)")
var re_convalidate = regexp.MustCompile("^(https?|tag|data):")
func memetize(honk *Honk) {
repl := func(x string) string {

6
genschemago.sh Normal file
View file

@ -0,0 +1,6 @@
echo "package main" > schema.go
echo "var sqlSchema = \`" >> schema.go
cat schema.sql >> schema.go
echo "\`" >> schema.go
go fmt schema.go

14
hfcs.go
View file

@ -33,7 +33,6 @@ type Filter struct {
IncludeAudience bool `json:",omitempty"`
Text string `json:",omitempty"`
re_text *regexp.Regexp
IsReply bool `json:",omitempty"`
IsAnnounce bool `json:",omitempty"`
AnnounceOf string `json:",omitempty"`
Reject bool `json:",omitempty"`
@ -307,13 +306,6 @@ func matchfilterX(h *Honk, f *Filter) string {
}
}
}
if match && f.IsReply {
match = false
if h.RID != "" {
match = true
rv += " reply"
}
}
if match && f.IsAnnounce {
match = false
if (f.AnnounceOf == "" && h.Oonker != "") || f.AnnounceOf == h.Oonker ||
@ -415,12 +407,6 @@ func unsee(honks []*Honk, userid int64) {
h.Open = ""
}
}
} else {
for _, h := range honks {
if h.Precis != "" {
h.Open = ""
}
}
}
}

42
honk.go
View file

@ -104,6 +104,8 @@ type Honk struct {
Time *Time
Mentions []Mention
Badonks []Badonk
Wonkles string
Guesses template.HTML
}
type Badonk struct {
@ -178,6 +180,10 @@ func (honk *Honk) IsReacted() bool {
return honk.Flags&flagIsReacted != 0
}
func (honk *Honk) IsWonked() bool {
return honk.Flags&flagIsWonked != 0
}
type Donk struct {
FileID int64
XID string
@ -373,42 +379,6 @@ func main() {
return
}
chpass(args[1])
case "follow":
if len(args) < 3 {
fmt.Printf("usage: honk follow username url\n")
return
}
user, err := butwhatabout(args[1])
if err != nil {
fmt.Printf("user not found\n")
return
}
var meta HonkerMeta
mj, _ := jsonify(&meta)
honkerid, err := savehonker(user, args[2], "", "presub", "", mj)
if err != nil {
fmt.Printf("had some trouble with that: %s\n", err)
return
}
followyou(user, honkerid, true)
case "unfollow":
if len(args) < 3 {
fmt.Printf("usage: honk unfollow username url\n")
return
}
user, err := butwhatabout(args[1])
if err != nil {
fmt.Printf("user not found\n")
return
}
row := db.QueryRow("select honkerid from honkers where xid = ? and userid = ? and flavor in ('sub')", args[2], user.ID)
var honkerid int64
err = row.Scan(&honkerid)
if err != nil {
fmt.Printf("sorry couldn't find them\n")
return
}
unfollowyou(user, honkerid, true)
case "cleanup":
arg := "30"
if len(args) > 1 {

51
hoot.go
View file

@ -26,7 +26,6 @@ import (
"github.com/andybalholm/cascadia"
"golang.org/x/net/html"
"humungus.tedunangst.com/r/webs/htfilter"
"humungus.tedunangst.com/r/webs/templates"
)
var tweetsel = cascadia.MustCompile("div[data-testid=tweetText]")
@ -55,11 +54,10 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
var htf htfilter.Filter
htf.Imager = func(node *html.Node) string {
alt := htfilter.GetAttr(node, "alt")
src := htfilter.GetAttr(node, "src")
if htfilter.HasClass(node, "Emoji") || strings.HasSuffix(src, ".svg") {
if htfilter.HasClass(node, "Emoji") && alt != "" {
return alt
}
return string(templates.Sprintf(" <img src='%s' alt='%s'>", src, alt))
return fmt.Sprintf(" <img src='%s'>", htfilter.GetAttr(node, "src"))
}
var buf strings.Builder
@ -67,6 +65,7 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
divs := tweetsel.MatchAll(root)
for i, div := range divs {
{
twp := div.Parent.Parent.Parent.Parent.Parent
link := url
alink := linksel.MatchFirst(twp)
@ -98,6 +97,50 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
text := htf.NodeText(div)
text = strings.Replace(text, "\n", " ", -1)
fmt.Fprintf(&buf, "> @%s: %s\n", author, text)
continue
}
twp := div.Parent.Parent.Parent.Parent.Parent
link := url
alink := linksel.MatchFirst(twp)
if alink == nil {
if i != 0 {
dlog.Printf("missing link")
continue
}
} else {
link = "https://twitter.com" + htfilter.GetAttr(alink, "href")
}
replto := replyingto.MatchFirst(twp)
if replto != nil {
continue
}
authormatch := authorregex.FindStringSubmatch(link)
if len(authormatch) < 2 {
dlog.Printf("no author?: %s", link)
continue
}
author := authormatch[1]
if wanted == "" {
wanted = author
}
if author != wanted {
continue
}
for _, img := range imgsel.MatchAll(twp) {
img.Parent.RemoveChild(img)
div.AppendChild(img)
}
text := htf.NodeText(div)
text = strings.Replace(text, "\n", " ", -1)
text = re_removepics.ReplaceAllString(text, "")
if seen[text] {
continue
}
fmt.Fprintf(&buf, "> @%s: %s\n", author, text)
seen[text] = true
}
return buf.String()
}

View file

@ -210,7 +210,7 @@ func importMastotooters(user *WhatAbout, source string) {
name := ""
flavor := "peep"
combos := ""
_, err := savehonker(user, url, name, flavor, combos, mj)
err := savehonker(user, url, name, flavor, combos, mj)
if err != nil {
elog.Printf("trouble with a honker: %s", err)
}

View file

@ -1,5 +1,5 @@
PROGS=autobonker gettoken saytheday sprayandpray youvegothonks
PROGS=autobonker gettoken saytheday sprayandpray wonkawonk youvegothonks
all: $(PROGS)
@ -18,5 +18,8 @@ saytheday: saytheday.go
sprayandpray: sprayandpray.go
go build sprayandpray.go
wonkawonk: wonkawonk.go fetch.go
go build wonkawonk.go fetch.go
youvegothonks: youvegothonks.go
go build youvegothonks.go

79
toys/wonkawonk.go Normal file
View file

@ -0,0 +1,79 @@
package main
import (
"crypto/rand"
"flag"
"fmt"
"io/ioutil"
"log"
"math/big"
"net/http"
"net/url"
"os"
"strings"
)
var debugMode = false
func honkahonk(server, token, wonk, wonkles string) {
form := make(url.Values)
form.Add("token", token)
form.Add("action", "honk")
form.Add("noise", wonk)
form.Add("wonkles", wonkles)
apiurl := fmt.Sprintf("https://%s/api", server)
req, err := http.NewRequest("POST", apiurl, strings.NewReader(form.Encode()))
if err != nil {
log.Fatal(err)
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client := http.DefaultClient
if debugMode {
client = debugClient
}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
answer, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != 200 {
log.Fatalf("status: %d: %s", resp.StatusCode, answer)
}
}
func main() {
server := ""
token := ""
wonkles := ""
flag.StringVar(&server, "server", server, "server to connnect")
flag.StringVar(&token, "token", token, "auth token to use")
flag.StringVar(&wonkles, "wonkles", wonkles, "wordlist to use")
flag.BoolVar(&debugMode, "debug", debugMode, "debug mode")
flag.Parse()
if server == "" || token == "" || wonkles == "" {
flag.Usage()
os.Exit(1)
}
wordlist, err := fetchsome(wonkles)
if err != nil {
log.Printf("error fetching wonkles: %s", err)
}
var words []string
for _, w := range strings.Split(string(wordlist), "\n") {
words = append(words, w)
}
max := big.NewInt(int64(len(words)))
i, _ := rand.Int(rand.Reader, max)
wonk := words[i.Int64()]
log.Printf("picking: %s", wonk)
honkahonk(server, token, wonk, wonkles)
}

View file

@ -22,7 +22,7 @@ import (
"time"
)
var myVersion = 42
var myVersion = 41
type dbexecer interface {
Exec(query string, args ...interface{}) (sql.Result, error)
@ -206,38 +206,6 @@ func upgradedb() {
doordie(db, "update config set value = 41 where key = 'dbversion'")
fallthrough
case 41:
tx, err := db.Begin()
if err != nil {
elog.Fatal(err)
}
rows, err := tx.Query("select honkid, noise from honks where format = 'markdown' and precis <> ''")
if err != nil {
elog.Fatal(err)
}
m := make(map[int64]string)
var dummy Honk
for rows.Next() {
err = rows.Scan(&dummy.ID, &dummy.Noise)
if err != nil {
elog.Fatal(err)
}
precipitate(&dummy)
m[dummy.ID] = dummy.Noise
}
rows.Close()
for id, noise := range m {
_, err = tx.Exec("update honks set noise = ? where honkid = ?", noise, id)
if err != nil {
elog.Fatal(err)
}
}
err = tx.Commit()
if err != nil {
elog.Fatal(err)
}
doordie(db, "update config set value = 42 where key = 'dbversion'")
fallthrough
case 42:
default:
elog.Fatalf("can't upgrade unknown version %d", dbversion)

View file

@ -21,14 +21,20 @@
<p><label class="button" for="reaction">reaction:</label>
<select tabindex=1 name="reaction">
<option {{ and (eq .User.Options.Reaction "none") "selected" }}>none</option>
<option {{ and (eq .User.Options.Reaction "\U0001F596") "selected" }}>{{ "\U0001F596" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F61E") "selected" }}>{{ "\U0001F61E" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F937") "selected" }}>{{ "\U0001F937" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F648") "selected" }}>{{ "\U0001F648" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F9BE") "selected" }}>{{ "\U0001F9BE" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F346") "selected" }}>{{ "\U0001F346" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F351") "selected" }}>{{ "\U0001F351" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F32E") "selected" }}>{{ "\U0001F32E" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F951") "selected" }}>{{ "\U0001F951" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F5FF") "selected" }}>{{ "\U0001F5FF" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F99A") "selected" }}>{{ "\U0001F99A" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F3BB") "selected" }}>{{ "\U0001F3BB" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001FA93") "selected" }}>{{ "\U0001FA93" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F9EF") "selected" }}>{{ "\U0001F9EF" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F1EB") "selected" }}>{{ "\U0001F1EB" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F1FD") "selected" }}>{{ "\U0001F1FD" }}</option>
</select>
<p><button>update settings</button>
</form>

View file

@ -20,8 +20,6 @@ Honk Filtering and Censorship System
<input tabindex=1 type="checkbox" id="incaud" name="incaud" value="yes"><span></span></label></span>
<p><label for="filttext">text matches:</label><br>
<input tabindex=1 type="text" name="filttext" value="" autocomplete=off>
<p><span><label class=button for="isreply">is reply:
<input tabindex=1 type="checkbox" id="isreply" name="isreply" value="yes"><span></span></label></span>
<p><span><label class=button for="isannounce">is announce:
<input tabindex=1 type="checkbox" id="isannounce" name="isannounce" value="yes"><span></span></label></span>
<p><label for="announceof">announce of:</label><br>
@ -56,7 +54,6 @@ Honk Filtering and Censorship System
{{ with .Notes }}<p>Notes: {{ . }}{{ end }}
<p>Date: {{ .Date.Format "2006-01-02" }}
{{ with .Actor }}<p>Who: {{ . }}{{ end }} {{ with .IncludeAudience }} (inclusive) {{ end }}
{{ if .IsReply }}<p>Reply: y{{ end }}
{{ if .IsAnnounce }}<p>Announce: {{ .AnnounceOf }}{{ end }}
{{ with .Text }}<p>Text: {{ . }}{{ end }}
<p>Actions: {{ range .Actions }} {{ . }} {{ end }}

View file

@ -52,7 +52,7 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
</header>
<p>
<details class="noise" {{ .Open }} >
<summary>{{ .HTPrecis }}<p></summary>
<summary>{{ .HTPrecis }}</summary>
<p>{{ .HTPrecis }}
<p class="content">{{ .HTML }}
{{ with .Time }}
@ -89,6 +89,15 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
{{ end }}
</details>
{{ end }}
{{ if eq .Honk.What "wonked" }}
<p>
{{ if and $bonkcsrf .Honk.IsWonked }}
{{ .Honk.Guesses }}
<p>{{ .Honk.Noise }}
{{ else }}
<button class="playit" data-noise="{{ .Honk.Noise }}" data-wonk="{{ .Honk.Wonkles }}">it's play time!</button>
{{ end }}
{{ end }}
{{ if and $bonkcsrf (not $IsPreview) }}
<p>
<details class="actions">

View file

@ -14,7 +14,7 @@
<p id="donkdescriptor"><label for=donkdesc>description:</label><br>
<input type="text" name="donkdesc" value="{{ .DonkDesc }}" autocomplete=off>
{{ with .SavedPlace }}
<p><button id=checkinbutton type=button>assassination coordinates</button>
<p><button id=checkinbutton type=button>checkin</button>
<div id=placedescriptor>
<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 }}">
@ -22,7 +22,7 @@
<label>lon: </label><input type="text" size=9 name="placelong" id=placelonginput value="{{ .Longitude }}">
</div>
{{ else }}
<p><button id=checkinbutton type=button>assassination coordinates</button>
<p><button id=checkinbutton type=button>checkin</button>
<div id=placedescriptor class="hide">
<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="">

View file

@ -139,6 +139,7 @@ function fillinhonks(xhr, glowit) {
} else {
holder.append(h)
}
}
relinklinks()
return lenhonks
@ -211,7 +212,7 @@ function switchtopage(name, arg) {
curpagestate.name = name
curpagestate.arg = arg
// get the holder for the target page
stash = name + ":" + arg
var stash = name + ":" + arg
holder = honksforpage[stash]
if (holder) {
honksonpage.prepend(holder)
@ -225,7 +226,7 @@ function switchtopage(name, arg) {
var args = hydrargs()
get("/hydra?" + encode(args), function(xhr) {
if (xhr.status == 200) {
fillinhonks(xhr, false)
var lenhonks = fillinhonks(xhr, false)
} else {
refreshupdate(" status: " + xhr.status)
}
@ -336,6 +337,12 @@ function relinklinks() {
el.onclick = function() {
flogit(el, "react", xid);
}
} else if (el.classList.contains("playit")) {
var noise = el.dataset.noise
var wonk = el.dataset.wonk
el.onclick = function() {
playit(el, noise, wonk, xid)
}
}
})
}
@ -351,7 +358,6 @@ function showhonkform(elem, rid, hname) {
elem.insertAdjacentElement('afterend', form)
}
var ridinput = document.getElementById("ridinput")
var honknoise = document.getElementById("honknoise")
if (rid) {
ridinput.value = rid
if (hname) {
@ -365,7 +371,7 @@ function showhonkform(elem, rid, hname) {
}
var updateinput = document.getElementById("updatexidinput")
updateinput.value = ""
honknoise.focus()
document.getElementById("honknoise").focus()
return false
}
function cancelhonking() {
@ -387,9 +393,9 @@ function hideelement(el) {
function updatedonker() {
var el = document.getElementById("donker")
el.children[1].textContent = el.children[0].value.slice(-20)
el = document.getElementById("donkdescriptor")
var el = document.getElementById("donkdescriptor")
el.style.display = ""
el = document.getElementById("saveddonkxid")
var el = document.getElementById("saveddonkxid")
el.value = ""
}
var checkinprec = 100.0
@ -411,19 +417,25 @@ function fillcheckin() {
gpsoptions.timeout = 2000
}, function(err) {
showelement("placedescriptor")
var el = document.getElementById("placenameinput")
el = document.getElementById("placenameinput")
el.value = err.message
}, gpsoptions)
}
}
function playit(elem, word, wordlist, xid) {
import('/wonk.js').then(module => {
makeaguess = module.makeaguess
module.addguesscontrols(elem, word, wordlist, xid)
})
}
function addemu(elem) {
const data = elem.alt
const box = document.getElementById("honknoise");
box.value += data;
}
function loademus() {
var div = document.getElementById("emupicker")
var request = new XMLHttpRequest()
div = document.getElementById("emupicker")
request = new XMLHttpRequest()
request.open('GET', '/emus')
request.onload = function() {
div.innerHTML = request.responseText

89
views/wonk.js Normal file
View file

@ -0,0 +1,89 @@
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=" + encodeURIComponent(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>guess</button>"
div.querySelector('button').onclick = function() {
makeaguess(this)
}
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 class='fontmonospace'>" + 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>guess</button>"
div.querySelector('button').onclick = function() {
makeaguess(this)
}
}
host.append(div)
btn.parentElement.remove()
}

150
web.go
View file

@ -381,6 +381,8 @@ func inbox(w http.ResponseWriter, r *http.Request) {
ilog.Printf("inbox message failed signature for %s from %s: %s", keyname, r.Header.Get("X-Forwarded-For"), err)
if keyname != "" {
ilog.Printf("bad signature from %s", keyname)
ilog.Writer().Write(payload)
ilog.Writer().Write([]byte{'\n'})
}
http.Error(w, "what did you call me?", http.StatusTeapot)
return
@ -419,9 +421,13 @@ func inbox(w http.ResponseWriter, r *http.Request) {
return
case "Question":
return
}
}
case "Note":
go xonksaver(user, j, origin)
return
}
}
ilog.Printf("unknown Update activity")
dumpactivity(j)
case "Undo":
obj, ok := j.GetMap("object")
if !ok {
@ -481,6 +487,8 @@ func serverinbox(w http.ResponseWriter, r *http.Request) {
ilog.Printf("inbox message failed signature for %s from %s: %s", keyname, r.Header.Get("X-Forwarded-For"), err)
if keyname != "" {
ilog.Printf("bad signature from %s", keyname)
ilog.Writer().Write(payload)
ilog.Writer().Write([]byte{'\n'})
}
http.Error(w, "what did you call me?", http.StatusTeapot)
return
@ -1322,6 +1330,21 @@ func zonkit(w http.ResponseWriter, r *http.Request) {
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
defer oldjonks.Flush()
@ -1555,7 +1578,7 @@ func submitdonk(w http.ResponseWriter, r *http.Request) (*Donk, error) {
return d, nil
}
func websubmithonk(w http.ResponseWriter, r *http.Request) {
func submitwebhonk(w http.ResponseWriter, r *http.Request) {
h := submithonk(w, r)
if h == nil {
return
@ -1597,6 +1620,10 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
if rid != "" {
what = "tonk"
}
wonkles := r.FormValue("wonkles")
if wonkles != "" {
what = "wonk"
}
honk = &Honk{
UserID: userinfo.UserID,
Username: userinfo.Username,
@ -1605,28 +1632,17 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
XID: xid,
Date: dt,
Format: format,
Wonkles: wonkles,
}
}
var convoy string
noise = strings.Replace(noise, "\r", "", -1)
if updatexid == "" && rid == "" {
noise = re_convoy.ReplaceAllStringFunc(noise, func(m string) string {
convoy = m[7:]
convoy = strings.TrimSpace(convoy)
if !re_convalidate.MatchString(convoy) {
convoy = ""
}
return ""
})
}
noise = quickrename(noise, userinfo.UserID)
noise = hooterize(noise)
honk.Noise = noise
precipitate(honk)
noise = honk.Noise
translate(honk)
var convoy string
if rid != "" {
xonk := getxonk(userinfo.UserID, rid)
if xonk == nil {
@ -1646,7 +1662,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
honk.RID = rid
if xonk.Precis != "" && honk.Precis == "" {
honk.Precis = xonk.Precis
if !re_dangerous.MatchString(honk.Precis) {
if !(strings.HasPrefix(honk.Precis, "DZ:") || strings.HasPrefix(honk.Precis, "re: re: re: ")) {
honk.Precis = "re: " + honk.Precis
}
}
@ -1680,19 +1696,12 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
}
if d != nil {
honk.Donks = append(honk.Donks, d)
donkxid = fmt.Sprintf("%s:%d", d.XID, d.FileID)
donkxid = d.XID
}
} else {
p := strings.Split(donkxid, ":")
xid := p[0]
xid := donkxid
url := fmt.Sprintf("https://%s/d/%s", serverName, xid)
var donk *Donk
if len(p) > 1 {
fileid, _ := strconv.ParseInt(p[1], 10, 0)
donk = finddonkid(fileid, url)
} else {
donk = finddonk(url)
}
donk := finddonk(url)
if donk != nil {
honk.Donks = append(honk.Donks, donk)
} else {
@ -1895,15 +1904,7 @@ func showcombos(w http.ResponseWriter, r *http.Request) {
}
}
func websubmithonker(w http.ResponseWriter, r *http.Request) {
h := submithonker(w, r)
if h == nil {
return
}
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
}
func submithonker(w http.ResponseWriter, r *http.Request) *Honker {
func submithonker(w http.ResponseWriter, r *http.Request) {
u := login.GetUserInfo(r)
user, _ := butwhatabout(u.Username)
name := strings.TrimSpace(r.FormValue("name"))
@ -1913,10 +1914,10 @@ func submithonker(w http.ResponseWriter, r *http.Request) *Honker {
combos = " " + combos + " "
honkerid, _ := strconv.ParseInt(r.FormValue("honkerid"), 10, 0)
re_namecheck := regexp.MustCompile("^[\\pL[:digit:]_.-]+$")
re_namecheck := regexp.MustCompile("[\\pL[:digit:]_.-]+")
if name != "" && !re_namecheck.MatchString(name) {
http.Error(w, "please use a plainer name", http.StatusInternalServerError)
return nil
return
}
var meta HonkerMeta
@ -1925,34 +1926,31 @@ func submithonker(w http.ResponseWriter, r *http.Request) *Honker {
defer honkerinvalidator.Clear(u.UserID)
// mostly dummy, fill in later...
h := &Honker{
ID: honkerid,
}
if honkerid > 0 {
if r.FormValue("delete") == "delete" {
unfollowyou(user, honkerid, false)
unfollowyou(user, honkerid)
stmtDeleteHonker.Exec(honkerid)
return h
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
return
}
if r.FormValue("unsub") == "unsub" {
unfollowyou(user, honkerid, false)
unfollowyou(user, honkerid)
}
if r.FormValue("sub") == "sub" {
followyou(user, honkerid, false)
followyou(user, honkerid)
}
_, err := stmtUpdateHonker.Exec(name, combos, mj, honkerid, u.UserID)
if err != nil {
elog.Printf("update honker err: %s", err)
return nil
return
}
return h
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
return
}
if url == "" {
http.Error(w, "subscribing to nothing?", http.StatusInternalServerError)
return nil
return
}
flavor := "presub"
@ -1960,17 +1958,13 @@ func submithonker(w http.ResponseWriter, r *http.Request) *Honker {
flavor = "peep"
}
var err error
honkerid, err = savehonker(user, url, name, flavor, combos, mj)
err := savehonker(user, url, name, flavor, combos, mj)
if err != nil {
http.Error(w, "had some trouble with that: "+err.Error(), http.StatusInternalServerError)
return nil
return
}
if flavor == "presub" {
followyou(user, honkerid, false)
}
h.ID = honkerid
return h
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
}
func hfcspage(w http.ResponseWriter, r *http.Request) {
@ -2007,7 +2001,6 @@ func savehfcs(w http.ResponseWriter, r *http.Request) {
filt.Actor = strings.TrimSpace(r.FormValue("actor"))
filt.IncludeAudience = r.FormValue("incaud") == "yes"
filt.Text = strings.TrimSpace(r.FormValue("filttext"))
filt.IsReply = r.FormValue("isreply") == "yes"
filt.IsAnnounce = r.FormValue("isannounce") == "yes"
filt.AnnounceOf = strings.TrimSpace(r.FormValue("announceof"))
filt.Reject = r.FormValue("doreject") == "yes"
@ -2123,29 +2116,11 @@ func somedays() string {
return fmt.Sprintf("%d", secs)
}
func lookatme(ava string) string {
if strings.Contains(ava, serverName+"/"+userSep) {
idx := strings.LastIndexByte(ava, '/')
if idx < len(ava) {
name := ava[idx+1:]
user, _ := butwhatabout(name)
if user != nil && user.URL == ava {
return user.Options.Avatar
}
}
}
return ""
}
func avatate(w http.ResponseWriter, r *http.Request) {
if develMode {
loadAvatarColors()
}
n := r.FormValue("a")
if redir := lookatme(n); redir != "" {
http.Redirect(w, r, redir, http.StatusSeeOther)
return
}
a := genAvatar(n)
if !develMode {
w.Header().Set("Cache-Control", "max-age="+somedays())
@ -2356,7 +2331,7 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
if h == nil {
return
}
fmt.Fprintf(w, "%s", h.XID)
w.Write([]byte(h.XID))
case "donk":
d, err := submitdonk(w, r)
if err != nil {
@ -2416,16 +2391,6 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
for rcpt := range rcpts {
go deliverate(0, userid, rcpt, msg, true)
}
case "gethonkers":
j := junk.New()
j["honkers"] = gethonkers(u.UserID)
j.Write(w)
case "savehonker":
h := submithonker(w, r)
if h == nil {
return
}
fmt.Fprintf(w, "%d", h.ID)
default:
http.Error(w, "unknown action", http.StatusNotFound)
return
@ -2468,7 +2433,7 @@ 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'; media-src 'self'; report-uri /csp-violation")
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)
})
}
@ -2588,6 +2553,7 @@ func serve() {
getters.HandleFunc("/style.css", serveviewasset)
getters.HandleFunc("/honkpage.js", serveviewasset)
getters.HandleFunc("/wonk.js", serveviewasset)
getters.HandleFunc("/misc.js", serveviewasset)
getters.HandleFunc("/local.css", servedataasset)
getters.HandleFunc("/local.js", servedataasset)
@ -2600,6 +2566,8 @@ func serve() {
getters.HandleFunc("/logout", login.LogoutFunc)
getters.HandleFunc("/help/{name:[\\pL[:digit:]_.-]+}", servehelp)
getters.HandleFunc("/bloat/wonkles", servewonkles)
loggedin := mux.NewRoute().Subrouter()
loggedin.Use(login.Required)
loggedin.HandleFunc("/first", homepage)
@ -2615,7 +2583,7 @@ func serve() {
loggedin.HandleFunc("/xzone", xzone)
loggedin.HandleFunc("/newhonk", newhonkpage)
loggedin.HandleFunc("/edit", edithonkpage)
loggedin.Handle("/honk", login.CSRFWrap("honkhonk", http.HandlerFunc(websubmithonk)))
loggedin.Handle("/honk", login.CSRFWrap("honkhonk", http.HandlerFunc(submitwebhonk)))
loggedin.Handle("/bonk", login.CSRFWrap("honkhonk", http.HandlerFunc(submitbonk)))
loggedin.Handle("/zonkit", login.CSRFWrap("honkhonk", http.HandlerFunc(zonkit)))
loggedin.Handle("/savehfcs", login.CSRFWrap("filter", http.HandlerFunc(savehfcs)))
@ -2630,7 +2598,7 @@ func serve() {
loggedin.HandleFunc("/q", showsearch)
loggedin.HandleFunc("/hydra", webhydra)
loggedin.HandleFunc("/emus", showemus)
loggedin.Handle("/submithonker", login.CSRFWrap("submithonker", http.HandlerFunc(websubmithonker)))
loggedin.Handle("/submithonker", login.CSRFWrap("submithonker", http.HandlerFunc(submithonker)))
err = http.Serve(listener, mux)
if err != nil {