Compare commits

...

45 Commits

Author SHA1 Message Date
Dirk Nederveen 01674ef092
Update dockerfiles 2023-03-27 08:56:18 +02:00
Dirk Nederveen 6e680ec97f
Add docker files
Build: docker build
2023-03-27 08:56:14 +02:00
Ted Unangst 10bca44dc5 we should support Update for more types than Note 2023-03-25 16:29:50 -04:00
Ted Unangst fc567f7f69 m 2023-03-25 15:10:30 -04:00
Ted Unangst 353a3b27f6 for image types, prefer the original over attachments 2023-03-25 15:09:53 -04:00
Ted Unangst b5470175c7 allow setting context by hand 2023-03-25 14:46:11 -04:00
Ted Unangst 9e43ccbb88 Added tag v0.9.91 for changeset d7c3a01e7aae 2023-03-17 14:29:34 -04:00
Ted Unangst 67c2d983bd that should do it 2023-03-17 14:29:22 -04:00
Ted Unangst 2a8f20feff quiet a log error 2023-03-17 14:28:29 -04:00
Ted Unangst ae8d1909d8 use the right variable 2023-03-17 14:24:15 -04:00
Ted Unangst deec523437 Added tag v0.9.9 for changeset 4b8cf31560b7 2023-03-17 10:46:01 -04:00
Ted Unangst 4f8a33eb2b 0.9.9 release 2023-03-17 10:45:51 -04:00
Ted Unangst 7058ecd1d0 clean up the dust 2023-03-17 10:45:25 -04:00
Ted Unangst 31a9ea6a08 need to allow media src for le memes 2023-03-15 17:01:30 -04:00
Ted Unangst 2eb5b9d3c0 these logs are annoying 2023-03-15 15:43:57 -04:00
Ted Unangst 858ce2f291 allow filtering of replies 2023-03-15 15:26:46 -04:00
Ted Unangst af2deab137 revert to sending summary for images, it should work 2023-03-09 12:32:53 -05:00
Ted Unangst a857fdd06c only dumb it down for images, stuff like PDF should retain name 2023-03-09 02:00:12 -05:00
Ted Unangst dab8de6670 don't drop the donk! sometimes preview would find the wrong one on resubmit. 2023-03-09 01:57:20 -05:00
Ted Unangst b261f73c49 some pleroma frontends apparently use notice urls 2023-03-09 00:54:59 -05:00
Ted Unangst bf9e65d699 simplify image descriptions so that lesser implementations can find them 2023-03-09 00:51:33 -05:00
Ted Unangst 7f8d2068fd m 2023-03-06 17:46:50 -05:00
Ted Unangst 2559b0cf16 experiment with allowing user avatar to be visible 2023-03-06 17:42:30 -05:00
Ted Unangst ff5b731644 newlines in error messages 2023-03-02 23:37:16 -05:00
Ted Unangst ba9d745efa need to query for the sub here 2023-03-02 23:34:54 -05:00
Ted Unangst e965f7090f command line follow and unfollow 2023-03-01 14:48:50 -05:00
Ted Unangst e8d1d64f1c namecheck regexp should match whole string 2023-02-26 12:08:43 -05:00
Ted Unangst 5e481273df rename checkin to assassination coordinates as benjojo did 2023-02-24 13:42:30 -05:00
Ted Unangst e9813defe2 genschema isn't used anymore 2023-02-24 13:17:30 -05:00
Ted Unangst 23117ad450 database upgrade to fixup the subject lines 2023-02-24 13:09:45 -05:00
Ted Unangst 108cd4fff3 remove excess logging 2023-02-24 12:59:22 -05:00
Ted Unangst 55ece74faa only markdown precis if we found a new one 2023-02-23 18:32:24 -05:00
Ted Unangst 5eb2821d10 note that some old posts may have two subjects now 2023-02-23 18:26:43 -05:00
Ted Unangst 65face4f35 consistently process precis as html.
only do the markdown conversion once and early.
2023-02-23 18:19:37 -05:00
Ted Unangst ed13b68989 collapse the danger honks by default when logged out 2023-02-22 15:04:24 -05:00
Ted Unangst b6efa7d4bd js lint from kuijsten 2023-02-22 14:56:26 -05:00
Ted Unangst ca9f48106c remove very old dead code which is confusing 2023-02-19 19:45:09 -05:00
Ted Unangst 65a27bf359 cleanup up emoji in hoots 2023-02-19 19:39:13 -05:00
Ted Unangst 4ed4ae3186 seasonal rotation of the reactions 2023-02-19 17:58:27 -05:00
Ted Unangst 398d430e97 wonkles are gone 2023-02-19 17:47:45 -05:00
Ted Unangst e08c21228c API access for honkers. 2023-02-19 17:46:59 -05:00
Ted Unangst ad5a149f64 safer to use templates sprintf to build html 2023-02-11 19:56:27 -05:00
Ted Unangst 9b8018ff26 alt text for hoot images 2023-02-11 19:46:29 -05:00
Ted Unangst 6d52b4f492 remove wonk support 2023-02-07 20:35:38 -05:00
Ted Unangst 628fc34ae4 all inclusive danger zone 2023-02-05 20:42:14 -05:00
29 changed files with 375 additions and 467 deletions

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
honk.db*
blob.db*
./honk
.git*

View File

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

20
Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM golang:1.19
RUN apt update && apt install -y libsqlite3-dev && rm -rf /var/cache/apt/*
RUN mkdir /honk-src
WORKDIR /honk-src
COPY go.mod go.sum /honk-src/
COPY . /honk-src/
RUN go get && go mod vendor
RUN make
RUN mv ./honk /bin/honk
CMD ["/bin/honk", "-datadir", "/honk-data"]
COPY docker-entrypoint.sh /honk-src/docker-entrypoint.sh
ENTRYPOINT ["/honk-src/docker-entrypoint.sh"]

View File

@ -511,7 +511,8 @@ 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_romalink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
var re_r0malink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
var re_roma1ink = regexp.MustCompile(`https://[[:alnum:].]+/notice/[[:alnum:]]+`)
var re_qtlinks = regexp.MustCompile(`>https://[^\s<]+<`)
func qutify(user *WhatAbout, content string) string {
@ -521,14 +522,11 @@ func qutify(user *WhatAbout, content string) string {
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) ||
if re_mast0link.MatchString(m) || re_masto1ink.MatchString(m) ||
re_misslink.MatchString(m) ||
re_honklink.MatchString(m) ||
re_romalink.MatchString(m) {
re_r0malink.MatchString(m) || re_roma1ink.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 {
@ -576,6 +574,7 @@ 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")
@ -687,11 +686,10 @@ 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
@ -820,12 +818,6 @@ 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"
}
@ -846,6 +838,9 @@ 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)
@ -873,7 +868,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" {
} else if at == "Document" || at == "Image" || (preferorig && at == "Link") {
mt = strings.ToLower(mt)
dlog.Printf("attachment: %s %s", mt, u)
if mt == "text/plain" || mt == "application/pdf" ||
@ -886,23 +881,42 @@ 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++
}
atts, _ := obj.GetArray("attachment")
for _, atti := range atts {
att, ok := atti.(junk.Junk)
if !ok {
ilog.Printf("attachment that wasn't map?")
continue
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
}
procatt(att)
}
if att, ok := obj.GetMap("attachment"); ok {
procatt(att)
if !preferorig {
atts, _ := obj.GetArray("attachment")
for _, atti := range atts {
att, ok := atti.(junk.Junk)
if !ok {
ilog.Printf("attachment that wasn't map?")
continue
}
procatt(att)
}
if att, ok := obj.GetMap("attachment"); ok {
procatt(att)
}
}
tags, _ := obj.GetArray("tag")
for _, tagi := range tags {
@ -1181,8 +1195,6 @@ 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()
@ -1190,8 +1202,6 @@ 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"
@ -1298,14 +1308,11 @@ 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"] = html.EscapeString(h.Precis)
jo["summary"] = h.Precis
jo["content"] = h.Noise
j["object"] = jo
case "bonk":
@ -1899,7 +1906,7 @@ func unfollowme(user *WhatAbout, who string, name string, j junk.Junk) {
}
}
func followyou(user *WhatAbout, honkerid int64) {
func followyou(user *WhatAbout, honkerid int64, sync bool) {
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')",
@ -1916,26 +1923,37 @@ func followyou(user *WhatAbout, honkerid int64) {
elog.Printf("error updating honker: %s", err)
return
}
go subsub(user, url, owner, folxid)
if sync {
subsub(user, url, owner, folxid)
} else {
go subsub(user, url, owner, folxid)
}
}
func unfollowyou(user *WhatAbout, honkerid int64) {
func unfollowyou(user *WhatAbout, honkerid int64, sync bool) {
db := opendatabase()
row := db.QueryRow("select xid, owner, folxid from honkers where honkerid = ? and userid = ? and flavor in ('sub')",
row := db.QueryRow("select xid, owner, folxid, flavor from honkers where honkerid = ? and userid = ? and flavor in ('unsub', 'peep', 'presub', 'sub')",
honkerid, user.ID)
var url, owner, folxid string
err := row.Scan(&url, &owner, &folxid)
var url, owner, folxid, flavor string
err := row.Scan(&url, &owner, &folxid, &flavor)
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
}
go itakeitallback(user, url, owner, folxid)
if sync {
itakeitallback(user, url, owner, folxid)
} else {
go itakeitallback(user, url, owner, folxid)
}
}
func followyou2(user *WhatAbout, j junk.Junk) {

View File

@ -14,54 +14,3 @@
// 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,9 +485,7 @@ 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)
@ -576,6 +574,20 @@ 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)
@ -897,20 +909,6 @@ 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
}
@ -978,7 +976,7 @@ func savexonker(what, value, flav, when string) {
stmtSaveXonker.Exec(what, value, flav, when)
}
func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) error {
func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) (int64, error) {
var owner string
if url[0] == '#' {
flavor = "peep"
@ -990,7 +988,7 @@ func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) error {
info, err := investigate(url)
if err != nil {
ilog.Printf("failed to investigate honker: %s", err)
return err
return 0, err
}
url = info.XID
if name == "" {
@ -1009,19 +1007,16 @@ func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) error {
} else {
err = fmt.Errorf("it seems you are already subscribed to them")
}
return err
return 0, err
}
res, err := stmtSaveHonker.Exec(user.ID, name, url, flavor, combos, owner, mj)
if err != nil {
elog.Print(err)
return err
return 0, err
}
honkerid, _ := res.LastInsertId()
if flavor == "presub" {
followyou(user, honkerid)
}
return nil
return honkerid, nil
}
func cleanupdb(arg string) {
@ -1098,7 +1093,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, stmtGetFileData, stmtSaveFileData, stmtSaveFile *sql.Stmt
var stmtFindFile, stmtFindFileId, 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
@ -1168,6 +1163,7 @@ 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 (?, ?, ?, ?, '', '', '', ?)")

15
docker-entrypoint.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
if [ ! -r "/honk-data/honk.db" ]; then
set -u
(
echo "$HONK_USERNAME"
echo "$HONK_PASSWORD"
echo "${HONK_LISTEN_ADDR:-"0.0.0.0:8080"}"
echo "${HONK_SERVER_HOSTNAME}"
) | honk -datadir "/honk-data" init
set +u
fi
exec $*

View File

@ -54,13 +54,6 @@ 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,6 +1,18 @@
changelog
=== next
=== 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.
+ Emu peeker

View File

@ -52,6 +52,8 @@ 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,6 +158,27 @@ 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,7 +74,8 @@ will become a horizontal rule.
.Pp
If the first line of a honk begins with
.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
Mentioning a specfic user such as
.Pq @user@example.social
@ -121,7 +122,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 check in to a location.
One may also live dangerously by posting assassination coordinates.
The available fields, all optional, are
.Ar name ,
.Ar url ,

View File

@ -142,6 +142,11 @@ 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,9 +181,6 @@ 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
}
@ -290,12 +287,11 @@ func imaginate(honk *Honk) {
htf.String(honk.Noise)
}
func translate(honk *Honk) {
if honk.Format == "html" {
return
}
var re_dangerous = regexp.MustCompile("^[a-zA-Z]{2}:")
func precipitate(honk *Honk) {
noise := honk.Noise
if strings.HasPrefix(noise, "DZ:") {
if re_dangerous.MatchString(noise) {
idx := strings.Index(noise, "\n")
if idx == -1 {
honk.Precis = noise
@ -304,8 +300,16 @@ func translate(honk *Honk) {
honk.Precis = noise[:idx]
noise = noise[idx+1:]
}
honk.Precis = markitzero(strings.TrimSpace(honk.Precis))
honk.Noise = noise
}
honk.Precis = markitzero(strings.TrimSpace(honk.Precis))
}
func translate(honk *Honk) {
if honk.Format == "html" {
return
}
noise := honk.Noise
var marker mz.Marker
marker.HashLinker = ontoreplacer
@ -421,6 +425,8 @@ 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 {

View File

@ -1,6 +0,0 @@
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,6 +33,7 @@ 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"`
@ -306,6 +307,13 @@ 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 ||
@ -407,6 +415,12 @@ func unsee(honks []*Honk, userid int64) {
h.Open = ""
}
}
} else {
for _, h := range honks {
if h.Precis != "" {
h.Open = ""
}
}
}
}

42
honk.go
View File

@ -104,8 +104,6 @@ type Honk struct {
Time *Time
Mentions []Mention
Badonks []Badonk
Wonkles string
Guesses template.HTML
}
type Badonk struct {
@ -180,10 +178,6 @@ 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
@ -379,6 +373,42 @@ 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 {

53
hoot.go
View File

@ -26,6 +26,7 @@ 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]")
@ -54,10 +55,11 @@ 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")
if htfilter.HasClass(node, "Emoji") && alt != "" {
src := htfilter.GetAttr(node, "src")
if htfilter.HasClass(node, "Emoji") || strings.HasSuffix(src, ".svg") {
return alt
}
return fmt.Sprintf(" <img src='%s'>", htfilter.GetAttr(node, "src"))
return string(templates.Sprintf(" <img src='%s' alt='%s'>", src, alt))
}
var buf strings.Builder
@ -65,41 +67,6 @@ 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)
if alink == nil {
if i != 0 {
dlog.Printf("missing link")
continue
}
} else {
alink = alink.Parent
link = "https://twitter.com" + htfilter.GetAttr(alink, "href")
}
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)
fmt.Fprintf(&buf, "> @%s: %s\n", author, text)
continue
}
twp := div.Parent.Parent.Parent.Parent.Parent
link := url
alink := linksel.MatchFirst(twp)
@ -109,12 +76,9 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
continue
}
} else {
alink = alink.Parent
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)
@ -133,14 +97,7 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
}
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 wonkawonk youvegothonks
PROGS=autobonker gettoken saytheday sprayandpray youvegothonks
all: $(PROGS)
@ -18,8 +18,5 @@ 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

View File

@ -1,79 +0,0 @@
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 = 41
var myVersion = 42
type dbexecer interface {
Exec(query string, args ...interface{}) (sql.Result, error)
@ -206,6 +206,38 @@ 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,20 +21,14 @@
<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 "\U0001F61E") "selected" }}>{{ "\U0001F61E" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F937") "selected" }}>{{ "\U0001F937" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F596") "selected" }}>{{ "\U0001F596" }}</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 "\U0001F1EB") "selected" }}>{{ "\U0001F1EB" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F1FD") "selected" }}>{{ "\U0001F1FD" }}</option>
<option {{ and (eq .User.Options.Reaction "\U0001F9EF") "selected" }}>{{ "\U0001F9EF" }}</option>
</select>
<p><button>update settings</button>
</form>

View File

@ -20,6 +20,8 @@ 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>
@ -54,6 +56,7 @@ 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 }}</summary>
<summary>{{ .HTPrecis }}<p></summary>
<p>{{ .HTPrecis }}
<p class="content">{{ .HTML }}
{{ with .Time }}
@ -89,15 +89,6 @@ 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>checkin</button>
<p><button id=checkinbutton type=button>assassination coordinates</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>checkin</button>
<p><button id=checkinbutton type=button>assassination coordinates</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,7 +139,6 @@ function fillinhonks(xhr, glowit) {
} else {
holder.append(h)
}
}
relinklinks()
return lenhonks
@ -212,7 +211,7 @@ function switchtopage(name, arg) {
curpagestate.name = name
curpagestate.arg = arg
// get the holder for the target page
var stash = name + ":" + arg
stash = name + ":" + arg
holder = honksforpage[stash]
if (holder) {
honksonpage.prepend(holder)
@ -226,7 +225,7 @@ function switchtopage(name, arg) {
var args = hydrargs()
get("/hydra?" + encode(args), function(xhr) {
if (xhr.status == 200) {
var lenhonks = fillinhonks(xhr, false)
fillinhonks(xhr, false)
} else {
refreshupdate(" status: " + xhr.status)
}
@ -337,12 +336,6 @@ 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)
}
}
})
}
@ -358,6 +351,7 @@ 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) {
@ -371,7 +365,7 @@ function showhonkform(elem, rid, hname) {
}
var updateinput = document.getElementById("updatexidinput")
updateinput.value = ""
document.getElementById("honknoise").focus()
honknoise.focus()
return false
}
function cancelhonking() {
@ -393,9 +387,9 @@ function hideelement(el) {
function updatedonker() {
var el = document.getElementById("donker")
el.children[1].textContent = el.children[0].value.slice(-20)
var el = document.getElementById("donkdescriptor")
el = document.getElementById("donkdescriptor")
el.style.display = ""
var el = document.getElementById("saveddonkxid")
el = document.getElementById("saveddonkxid")
el.value = ""
}
var checkinprec = 100.0
@ -417,25 +411,19 @@ function fillcheckin() {
gpsoptions.timeout = 2000
}, function(err) {
showelement("placedescriptor")
el = document.getElementById("placenameinput")
var 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() {
div = document.getElementById("emupicker")
request = new XMLHttpRequest()
var div = document.getElementById("emupicker")
var request = new XMLHttpRequest()
request.open('GET', '/emus')
request.onload = function() {
div.innerHTML = request.responseText

View File

@ -1,89 +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=" + 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()
}

148
web.go
View File

@ -381,8 +381,6 @@ 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
@ -421,13 +419,9 @@ 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)
go xonksaver(user, j, origin)
case "Undo":
obj, ok := j.GetMap("object")
if !ok {
@ -487,8 +481,6 @@ 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
@ -1330,21 +1322,6 @@ 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()
@ -1578,7 +1555,7 @@ func submitdonk(w http.ResponseWriter, r *http.Request) (*Donk, error) {
return d, nil
}
func submitwebhonk(w http.ResponseWriter, r *http.Request) {
func websubmithonk(w http.ResponseWriter, r *http.Request) {
h := submithonk(w, r)
if h == nil {
return
@ -1620,10 +1597,6 @@ 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,
@ -1632,17 +1605,28 @@ 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 {
@ -1662,7 +1646,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
honk.RID = rid
if xonk.Precis != "" && honk.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
}
}
@ -1696,12 +1680,19 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
}
if d != nil {
honk.Donks = append(honk.Donks, d)
donkxid = d.XID
donkxid = fmt.Sprintf("%s:%d", d.XID, d.FileID)
}
} else {
xid := donkxid
p := strings.Split(donkxid, ":")
xid := p[0]
url := fmt.Sprintf("https://%s/d/%s", serverName, xid)
donk := finddonk(url)
var donk *Donk
if len(p) > 1 {
fileid, _ := strconv.ParseInt(p[1], 10, 0)
donk = finddonkid(fileid, url)
} else {
donk = finddonk(url)
}
if donk != nil {
honk.Donks = append(honk.Donks, donk)
} else {
@ -1904,7 +1895,15 @@ func showcombos(w http.ResponseWriter, r *http.Request) {
}
}
func submithonker(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 {
u := login.GetUserInfo(r)
user, _ := butwhatabout(u.Username)
name := strings.TrimSpace(r.FormValue("name"))
@ -1914,10 +1913,10 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
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
return nil
}
var meta HonkerMeta
@ -1926,31 +1925,34 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
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)
unfollowyou(user, honkerid, false)
stmtDeleteHonker.Exec(honkerid)
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
return
return h
}
if r.FormValue("unsub") == "unsub" {
unfollowyou(user, honkerid)
unfollowyou(user, honkerid, false)
}
if r.FormValue("sub") == "sub" {
followyou(user, honkerid)
followyou(user, honkerid, false)
}
_, err := stmtUpdateHonker.Exec(name, combos, mj, honkerid, u.UserID)
if err != nil {
elog.Printf("update honker err: %s", err)
return
return nil
}
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
return
return h
}
if url == "" {
http.Error(w, "subscribing to nothing?", http.StatusInternalServerError)
return
return nil
}
flavor := "presub"
@ -1958,13 +1960,17 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
flavor = "peep"
}
err := savehonker(user, url, name, flavor, combos, mj)
var err error
honkerid, err = savehonker(user, url, name, flavor, combos, mj)
if err != nil {
http.Error(w, "had some trouble with that: "+err.Error(), http.StatusInternalServerError)
return
return nil
}
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
if flavor == "presub" {
followyou(user, honkerid, false)
}
h.ID = honkerid
return h
}
func hfcspage(w http.ResponseWriter, r *http.Request) {
@ -2001,6 +2007,7 @@ 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"
@ -2116,11 +2123,29 @@ 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())
@ -2331,7 +2356,7 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
if h == nil {
return
}
w.Write([]byte(h.XID))
fmt.Fprintf(w, "%s", h.XID)
case "donk":
d, err := submitdonk(w, r)
if err != nil {
@ -2391,6 +2416,16 @@ 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
@ -2433,7 +2468,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'; 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'; media-src 'self'; report-uri /csp-violation")
next.ServeHTTP(w, r)
})
}
@ -2553,7 +2588,6 @@ 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)
@ -2566,8 +2600,6 @@ 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)
@ -2583,7 +2615,7 @@ func serve() {
loggedin.HandleFunc("/xzone", xzone)
loggedin.HandleFunc("/newhonk", newhonkpage)
loggedin.HandleFunc("/edit", edithonkpage)
loggedin.Handle("/honk", login.CSRFWrap("honkhonk", http.HandlerFunc(submitwebhonk)))
loggedin.Handle("/honk", login.CSRFWrap("honkhonk", http.HandlerFunc(websubmithonk)))
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)))
@ -2598,7 +2630,7 @@ func serve() {
loggedin.HandleFunc("/q", showsearch)
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(websubmithonker)))
err = http.Serve(listener, mux)
if err != nil {