This commit is contained in:
commit
5de0395059
1
.hgtags
1
.hgtags
|
@ -25,3 +25,4 @@ b140f7a3216b820aa13f982e45ff42781d7a8f4a v0.8.2
|
|||
8a2a90379bf60d425fec114ff88f5fd9806a4965 v0.8.2
|
||||
808ef90260d5d81db1ec98fb8894588a3ac7b369 v0.8.3
|
||||
3ada67b721e7e4a478d0effacde14f36dc16e1de v0.8.4
|
||||
2e9969df06ddab8fa07999e91437dda28ec058ae v0.8.5
|
||||
|
|
4
README
4
README
|
@ -63,3 +63,7 @@ It is considered rude to make noise in a place of business.
|
|||
|
||||
The honk may be made on public property only when the person doing
|
||||
the honk has the permission of the owner of that property.
|
||||
|
||||
-- disclaimer
|
||||
|
||||
Do not use honk to contact emergency services.
|
||||
|
|
129
activity.go
129
activity.go
|
@ -19,6 +19,7 @@ import (
|
|||
"bytes"
|
||||
"crypto/rsa"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
|
@ -141,6 +142,22 @@ func GetJunkTimeout(url string, timeout time.Duration) (junk.Junk, error) {
|
|||
return j, nil
|
||||
}
|
||||
|
||||
func fetchsome(url string) ([]byte, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("error fetching %s: %s", url, err)
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, errors.New("not 200")
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
limiter := io.LimitReader(resp.Body, 10*1024*1024)
|
||||
io.Copy(&buf, limiter)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func savedonk(url string, name, desc, media string, localize bool) *Donk {
|
||||
if url == "" {
|
||||
return nil
|
||||
|
@ -154,22 +171,16 @@ func savedonk(url string, name, desc, media string, localize bool) *Donk {
|
|||
xid := xfiltrate()
|
||||
data := []byte{}
|
||||
if localize {
|
||||
resp, err := http.Get(url)
|
||||
fn := func() (interface{}, error) {
|
||||
return fetchsome(url)
|
||||
}
|
||||
ii, err := flightdeck.Call(url, fn)
|
||||
if err != nil {
|
||||
log.Printf("error fetching %s: %s", url, err)
|
||||
localize = false
|
||||
goto saveit
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
localize = false
|
||||
goto saveit
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
limiter := io.LimitReader(resp.Body, 10*1024*1024)
|
||||
io.Copy(&buf, limiter)
|
||||
data = ii.([]byte)
|
||||
|
||||
data = buf.Bytes()
|
||||
if len(data) == 10*1024*1024 {
|
||||
log.Printf("truncation likely")
|
||||
}
|
||||
|
@ -188,6 +199,12 @@ func savedonk(url string, name, desc, media string, localize bool) *Donk {
|
|||
format = "jpg"
|
||||
}
|
||||
xid = xid + "." + format
|
||||
} else if media == "application/pdf" {
|
||||
if len(data) > 1000000 {
|
||||
log.Printf("not saving large pdf")
|
||||
localize = false
|
||||
data = []byte{}
|
||||
}
|
||||
} else if len(data) > 100000 {
|
||||
log.Printf("not saving large attachment")
|
||||
localize = false
|
||||
|
@ -224,11 +241,20 @@ func needxonk(user *WhatAbout, x *Honk) bool {
|
|||
}
|
||||
return needxonkid(user, x.XID)
|
||||
}
|
||||
func needbonkid(user *WhatAbout, xid string) bool {
|
||||
return needxonkidX(user, xid, true)
|
||||
}
|
||||
func needxonkid(user *WhatAbout, xid string) bool {
|
||||
return needxonkidX(user, xid, false)
|
||||
}
|
||||
func needxonkidX(user *WhatAbout, xid string, isannounce bool) bool {
|
||||
if !strings.HasPrefix(xid, "https://") {
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(xid, user.URL+"/") {
|
||||
return false
|
||||
}
|
||||
if rejectorigin(user.ID, xid) {
|
||||
if rejectorigin(user.ID, xid, isannounce) {
|
||||
return false
|
||||
}
|
||||
if iszonked(user.ID, xid) {
|
||||
|
@ -277,7 +303,8 @@ var boxofboxes = cache.New(cache.Options{Filler: func(ident string) (*Box, bool)
|
|||
err := row.Scan(&info)
|
||||
if err != nil {
|
||||
log.Printf("need to get boxes for %s", ident)
|
||||
j, err := GetJunk(ident)
|
||||
var j junk.Junk
|
||||
j, err = GetJunk(ident)
|
||||
if err != nil {
|
||||
log.Printf("error getting boxes: %s", err)
|
||||
return nil, false
|
||||
|
@ -483,7 +510,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
} else {
|
||||
xid, _ = item.GetString("object")
|
||||
}
|
||||
if !needxonkid(user, xid) {
|
||||
if !needbonkid(user, xid) {
|
||||
return nil
|
||||
}
|
||||
log.Printf("getting bonk: %s", xid)
|
||||
|
@ -617,7 +644,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
xonk.Audience = append(xonk.Audience, xonk.Honker)
|
||||
xonk.Audience = oneofakind(xonk.Audience)
|
||||
|
||||
var mentions []string
|
||||
var mentions []Mention
|
||||
if obj != nil {
|
||||
ot, _ := obj.GetString("type")
|
||||
url, _ = obj.GetString("url")
|
||||
|
@ -697,7 +724,8 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
} else if at == "Document" || at == "Image" {
|
||||
mt = strings.ToLower(mt)
|
||||
log.Printf("attachment: %s %s", mt, u)
|
||||
if mt == "text/plain" || strings.HasPrefix(mt, "image") {
|
||||
if mt == "text/plain" || mt == "application/pdf" ||
|
||||
strings.HasPrefix(mt, "image") {
|
||||
localize = true
|
||||
}
|
||||
} else {
|
||||
|
@ -754,7 +782,9 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
xonk.Place = p
|
||||
}
|
||||
if tt == "Mention" {
|
||||
m, _ := tag.GetString("href")
|
||||
var m Mention
|
||||
m.Who, _ = tag.GetString("name")
|
||||
m.Where, _ = tag.GetString("href")
|
||||
mentions = append(mentions, m)
|
||||
}
|
||||
}
|
||||
|
@ -833,8 +863,9 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
xonk.Precis = precis
|
||||
xonk.Format = "html"
|
||||
xonk.Convoy = convoy
|
||||
xonk.Mentions = mentions
|
||||
for _, m := range mentions {
|
||||
if m == user.URL {
|
||||
if m.Where == user.URL {
|
||||
xonk.Whofore = 1
|
||||
}
|
||||
}
|
||||
|
@ -847,14 +878,8 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
log.Printf("didn't find old version for update: %s", xonk.XID)
|
||||
isUpdate = false
|
||||
} else {
|
||||
prev.Noise = xonk.Noise
|
||||
prev.Precis = xonk.Precis
|
||||
prev.Date = xonk.Date
|
||||
prev.Donks = xonk.Donks
|
||||
prev.Onts = xonk.Onts
|
||||
prev.Place = xonk.Place
|
||||
prev.Whofore = xonk.Whofore
|
||||
updatehonk(prev)
|
||||
xonk.ID = prev.ID
|
||||
updatehonk(&xonk)
|
||||
}
|
||||
}
|
||||
if !isUpdate && needxonk(user, &xonk) {
|
||||
|
@ -883,7 +908,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
convoy = currenttid
|
||||
}
|
||||
if convoy == "" {
|
||||
convoy = "missing-" + xfiltrate()
|
||||
convoy = "data:,missing-" + xfiltrate()
|
||||
currenttid = convoy
|
||||
}
|
||||
xonk.Convoy = convoy
|
||||
|
@ -1008,10 +1033,11 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
|
|||
jo["directMessage"] = true
|
||||
}
|
||||
mentions := bunchofgrapes(h.Noise)
|
||||
translate(h, true)
|
||||
translate(h)
|
||||
redoimages(h)
|
||||
jo["summary"] = html.EscapeString(h.Precis)
|
||||
jo["content"] = h.Noise
|
||||
if strings.HasPrefix(h.Precis, "DZ:") {
|
||||
if h.Precis != "" {
|
||||
jo["sensitive"] = true
|
||||
}
|
||||
|
||||
|
@ -1031,8 +1057,8 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
|
|||
for _, m := range mentions {
|
||||
t := junk.New()
|
||||
t["type"] = "Mention"
|
||||
t["name"] = m.who
|
||||
t["href"] = m.where
|
||||
t["name"] = m.Who
|
||||
t["href"] = m.Where
|
||||
tags = append(tags, t)
|
||||
}
|
||||
for _, o := range h.Onts {
|
||||
|
@ -1167,24 +1193,34 @@ func gimmejonk(xid string) ([]byte, bool) {
|
|||
return j, ok
|
||||
}
|
||||
|
||||
func honkworldwide(user *WhatAbout, honk *Honk) {
|
||||
jonk, _ := jonkjonk(user, honk)
|
||||
jonk["@context"] = itiswhatitis
|
||||
msg := jonk.ToBytes()
|
||||
|
||||
func boxuprcpts(user *WhatAbout, addresses []string, useshared bool) map[string]bool {
|
||||
rcpts := make(map[string]bool)
|
||||
for _, a := range honk.Audience {
|
||||
if a == thewholeworld || a == user.URL || strings.HasSuffix(a, "/followers") {
|
||||
for _, a := range addresses {
|
||||
if a == "" || a == thewholeworld || a == user.URL || strings.HasSuffix(a, "/followers") {
|
||||
continue
|
||||
}
|
||||
if a[0] == '%' {
|
||||
rcpts[a] = true
|
||||
continue
|
||||
}
|
||||
var box *Box
|
||||
ok := boxofboxes.Get(a, &box)
|
||||
if ok && honk.Public && box.Shared != "" {
|
||||
if ok && useshared && box.Shared != "" {
|
||||
rcpts["%"+box.Shared] = true
|
||||
} else {
|
||||
rcpts[a] = true
|
||||
}
|
||||
}
|
||||
return rcpts
|
||||
}
|
||||
|
||||
func honkworldwide(user *WhatAbout, honk *Honk) {
|
||||
jonk, _ := jonkjonk(user, honk)
|
||||
jonk["@context"] = itiswhatitis
|
||||
msg := jonk.ToBytes()
|
||||
|
||||
rcpts := boxuprcpts(user, honk.Audience, honk.Public)
|
||||
|
||||
if honk.Public {
|
||||
for _, h := range getdubs(user.ID) {
|
||||
if h.XID == user.URL {
|
||||
|
@ -1198,6 +1234,9 @@ func honkworldwide(user *WhatAbout, honk *Honk) {
|
|||
rcpts[h.XID] = true
|
||||
}
|
||||
}
|
||||
for _, f := range getbacktracks(honk.XID) {
|
||||
rcpts[f] = true
|
||||
}
|
||||
}
|
||||
for a := range rcpts {
|
||||
go deliverate(0, user.ID, a, msg)
|
||||
|
@ -1317,7 +1356,8 @@ var handfull = cache.New(cache.Options{Filler: func(name string) (string, bool)
|
|||
rel, _ := l.GetString("rel")
|
||||
t, _ := l.GetString("type")
|
||||
if rel == "self" && friendorfoe(t) {
|
||||
_, err := stmtSaveXonker.Exec(name, href, "fishname")
|
||||
when := time.Now().UTC().Format(dbtimeformat)
|
||||
_, err := stmtSaveXonker.Exec(name, href, "fishname", when)
|
||||
if err != nil {
|
||||
log.Printf("error saving fishname: %s", err)
|
||||
}
|
||||
|
@ -1430,7 +1470,8 @@ func ingestpubkey(origin string, obj junk.Junk) {
|
|||
log.Printf("error decoding %s pubkey: %s", keyname, err)
|
||||
return
|
||||
}
|
||||
_, err = stmtSaveXonker.Exec(keyname, data, "pubkey")
|
||||
when := time.Now().UTC().Format(dbtimeformat)
|
||||
_, err = stmtSaveXonker.Exec(keyname, data, "pubkey", when)
|
||||
if err != nil {
|
||||
log.Printf("error saving key: %s", err)
|
||||
}
|
||||
|
@ -1455,8 +1496,9 @@ func ingestboxes(origin string, obj junk.Junk) {
|
|||
outbox, _ := obj.GetString("outbox")
|
||||
sbox, _ := obj.GetString("endpoints", "sharedInbox")
|
||||
if inbox != "" {
|
||||
when := time.Now().UTC().Format(dbtimeformat)
|
||||
m := strings.Join([]string{inbox, outbox, sbox}, " ")
|
||||
_, err = stmtSaveXonker.Exec(ident, m, "boxes")
|
||||
_, err = stmtSaveXonker.Exec(ident, m, "boxes", when)
|
||||
if err != nil {
|
||||
log.Printf("error saving boxes: %s", err)
|
||||
}
|
||||
|
@ -1479,7 +1521,8 @@ func ingesthandle(origin string, obj junk.Junk) {
|
|||
}
|
||||
handle, _ = obj.GetString("preferredUsername")
|
||||
if handle != "" {
|
||||
_, err = stmtSaveXonker.Exec(xid, handle, "handle")
|
||||
when := time.Now().UTC().Format(dbtimeformat)
|
||||
_, err = stmtSaveXonker.Exec(xid, handle, "handle", when)
|
||||
if err != nil {
|
||||
log.Printf("error saving handle: %s", err)
|
||||
}
|
||||
|
|
10
admin.go
10
admin.go
|
@ -36,6 +36,9 @@ func adminscreen() {
|
|||
smcup := esc + "[?1049h"
|
||||
rmcup := esc + "[?1049l"
|
||||
|
||||
var avatarColors string
|
||||
getconfig("avatarcolors", &avatarColors)
|
||||
|
||||
messages := []*struct {
|
||||
name string
|
||||
label string
|
||||
|
@ -56,6 +59,11 @@ func adminscreen() {
|
|||
label: "login",
|
||||
text: string(loginMsg),
|
||||
},
|
||||
{
|
||||
name: "avatarcolors",
|
||||
label: "avatar colors (4 RGBA hex numbers)",
|
||||
text: string(avatarColors),
|
||||
},
|
||||
}
|
||||
cursel := 0
|
||||
|
||||
|
@ -239,7 +247,7 @@ func adminscreen() {
|
|||
stdout.Flush()
|
||||
}
|
||||
editing = false
|
||||
updateconfig(m.name, m.text)
|
||||
setconfig(m.name, m.text)
|
||||
hidecursor()
|
||||
drawscreen()
|
||||
}
|
||||
|
|
73
avatar.go
73
avatar.go
|
@ -16,13 +16,52 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha512"
|
||||
"image"
|
||||
"image/png"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func avatar(name string) []byte {
|
||||
var avatarcolors = [4][4]byte{
|
||||
{16, 0, 48, 255},
|
||||
{48, 0, 96, 255},
|
||||
{72, 0, 144, 255},
|
||||
{96, 0, 192, 255},
|
||||
}
|
||||
|
||||
func loadAvatarColors() {
|
||||
var colors string
|
||||
getconfig("avatarcolors", &colors)
|
||||
if colors == "" {
|
||||
return
|
||||
}
|
||||
r := bufio.NewReader(strings.NewReader(colors))
|
||||
for i := 0; i < 4; i++ {
|
||||
l, _ := r.ReadString(' ')
|
||||
for l == " " {
|
||||
l, _ = r.ReadString(' ')
|
||||
}
|
||||
l = strings.Trim(l, "# \n")
|
||||
if len(l) == 6 {
|
||||
l = l + "ff"
|
||||
}
|
||||
c, err := strconv.ParseUint(l, 16, 32)
|
||||
if err != nil {
|
||||
log.Printf("error reading avatar color %d: %s", i, err)
|
||||
continue
|
||||
}
|
||||
avatarcolors[i][0] = byte(c >> 24 & 0xff)
|
||||
avatarcolors[i][1] = byte(c >> 16 & 0xff)
|
||||
avatarcolors[i][2] = byte(c >> 8 & 0xff)
|
||||
avatarcolors[i][3] = byte(c >> 0 & 0xff)
|
||||
}
|
||||
}
|
||||
|
||||
func genAvatar(name string) []byte {
|
||||
h := sha512.New()
|
||||
h.Write([]byte(name))
|
||||
s := h.Sum(nil)
|
||||
|
@ -33,25 +72,25 @@ func avatar(name string) []byte {
|
|||
xx := i/16*16 + j/16
|
||||
x := s[xx]
|
||||
if x < 64 {
|
||||
img.Pix[p+0] = 16
|
||||
img.Pix[p+1] = 0
|
||||
img.Pix[p+2] = 48
|
||||
img.Pix[p+3] = 255
|
||||
img.Pix[p+0] = avatarcolors[0][0]
|
||||
img.Pix[p+1] = avatarcolors[0][1]
|
||||
img.Pix[p+2] = avatarcolors[0][2]
|
||||
img.Pix[p+3] = avatarcolors[0][3]
|
||||
} else if x < 128 {
|
||||
img.Pix[p+0] = 48
|
||||
img.Pix[p+1] = 0
|
||||
img.Pix[p+2] = 96
|
||||
img.Pix[p+3] = 255
|
||||
img.Pix[p+0] = avatarcolors[1][0]
|
||||
img.Pix[p+1] = avatarcolors[1][1]
|
||||
img.Pix[p+2] = avatarcolors[1][2]
|
||||
img.Pix[p+3] = avatarcolors[1][3]
|
||||
} else if x < 192 {
|
||||
img.Pix[p+0] = 72
|
||||
img.Pix[p+1] = 0
|
||||
img.Pix[p+2] = 144
|
||||
img.Pix[p+3] = 255
|
||||
img.Pix[p+0] = avatarcolors[2][0]
|
||||
img.Pix[p+1] = avatarcolors[2][1]
|
||||
img.Pix[p+2] = avatarcolors[2][2]
|
||||
img.Pix[p+3] = avatarcolors[2][3]
|
||||
} else {
|
||||
img.Pix[p+0] = 96
|
||||
img.Pix[p+1] = 0
|
||||
img.Pix[p+2] = 192
|
||||
img.Pix[p+3] = 255
|
||||
img.Pix[p+0] = avatarcolors[3][0]
|
||||
img.Pix[p+1] = avatarcolors[3][1]
|
||||
img.Pix[p+2] = avatarcolors[3][2]
|
||||
img.Pix[p+3] = avatarcolors[3][3]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
|
||||
"humungus.tedunangst.com/r/webs/gate"
|
||||
"humungus.tedunangst.com/r/webs/image"
|
||||
)
|
||||
|
||||
|
@ -38,7 +39,11 @@ type ShrinkerResult struct {
|
|||
Image *image.Image
|
||||
}
|
||||
|
||||
var shrinkgate = gate.NewLimiter(4)
|
||||
|
||||
func (s *Shrinker) Shrink(args *ShrinkerArgs, res *ShrinkerResult) error {
|
||||
shrinkgate.Start()
|
||||
defer shrinkgate.Finish()
|
||||
img, err := image.Vacuum(bytes.NewReader(args.Buf), args.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -68,6 +73,8 @@ func shrinkit(data []byte) (*image.Image, error) {
|
|||
return res.Image, nil
|
||||
}
|
||||
|
||||
var backendhooks []func()
|
||||
|
||||
func backendServer() {
|
||||
log.Printf("backend server running")
|
||||
shrinker := new(Shrinker)
|
||||
|
@ -87,7 +94,7 @@ func backendServer() {
|
|||
if err != nil {
|
||||
log.Panicf("unable to register shrinker: %s", err)
|
||||
}
|
||||
for _, h := range preservehooks {
|
||||
for _, h := range backendhooks {
|
||||
h()
|
||||
}
|
||||
srv.Accept(lis)
|
||||
|
|
80
database.go
80
database.go
|
@ -101,13 +101,16 @@ func gethonkers(userid int64) []*Honker {
|
|||
var honkers []*Honker
|
||||
for rows.Next() {
|
||||
h := new(Honker)
|
||||
var combos string
|
||||
err = rows.Scan(&h.ID, &h.UserID, &h.Name, &h.XID, &h.Flavor, &combos)
|
||||
h.Combos = strings.Split(strings.TrimSpace(combos), " ")
|
||||
var combos, meta string
|
||||
err = rows.Scan(&h.ID, &h.UserID, &h.Name, &h.XID, &h.Flavor, &combos, &meta)
|
||||
if err == nil {
|
||||
err = unjsonify(meta, &h.Meta)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("error scanning honker: %s", err)
|
||||
return nil
|
||||
continue
|
||||
}
|
||||
h.Combos = strings.Split(strings.TrimSpace(combos), " ")
|
||||
honkers = append(honkers, h)
|
||||
}
|
||||
return honkers
|
||||
|
@ -249,8 +252,10 @@ func gethonksbysearch(userid int64, q string, wanted int64) []*Honk {
|
|||
withhonker := 0
|
||||
site := ""
|
||||
withsite := 0
|
||||
withnotq := 0
|
||||
terms := strings.Split(q, " ")
|
||||
q = "%"
|
||||
notq := "%"
|
||||
for _, t := range terms {
|
||||
if strings.HasPrefix(t, "site:") {
|
||||
site = t[5:]
|
||||
|
@ -267,13 +272,27 @@ func gethonksbysearch(userid int64, q string, wanted int64) []*Honk {
|
|||
withhonker = 1
|
||||
continue
|
||||
}
|
||||
if t[0] == '-' {
|
||||
if t == "-" {
|
||||
continue
|
||||
}
|
||||
if len(notq) != 1 {
|
||||
notq += " "
|
||||
}
|
||||
notq += t[1:]
|
||||
continue
|
||||
}
|
||||
if len(q) != 1 {
|
||||
q += " "
|
||||
}
|
||||
q += t
|
||||
}
|
||||
q += "%"
|
||||
rows, err := stmtHonksBySearch.Query(wanted, userid, withsite, site, withhonker, honker, honker, q, userid)
|
||||
notq += "%"
|
||||
if notq != "%%" {
|
||||
withnotq = 1
|
||||
}
|
||||
rows, err := stmtHonksBySearch.Query(wanted, userid, withsite, site, withhonker, honker, honker, q, withnotq, notq, userid)
|
||||
honks := getsomehonks(rows, err)
|
||||
return honks
|
||||
}
|
||||
|
@ -413,6 +432,12 @@ func donksforhonks(honks []*Honk) {
|
|||
continue
|
||||
}
|
||||
h.Time = t
|
||||
case "mentions":
|
||||
err = unjsonify(j, &h.Mentions)
|
||||
if err != nil {
|
||||
log.Printf("error parsing mentions: %s", err)
|
||||
continue
|
||||
}
|
||||
case "oldrev":
|
||||
default:
|
||||
log.Printf("unknown meta genus: %s", genus)
|
||||
|
@ -491,7 +516,7 @@ func updatehonk(h *Honk) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = deleteextras(tx, h.ID)
|
||||
err = deleteextras(tx, h.ID, false)
|
||||
if err == nil {
|
||||
_, err = tx.Stmt(stmtUpdateHonk).Exec(h.Precis, h.Noise, h.Format, h.Whofore, dt, h.ID)
|
||||
}
|
||||
|
@ -527,10 +552,7 @@ func deletehonk(honkid int64) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = deleteextras(tx, honkid)
|
||||
if err == nil {
|
||||
_, err = tx.Stmt(stmtDeleteMeta).Exec(honkid, "nonsense")
|
||||
}
|
||||
err = deleteextras(tx, honkid, true)
|
||||
if err == nil {
|
||||
_, err = tx.Stmt(stmtDeleteHonk).Exec(honkid)
|
||||
}
|
||||
|
@ -580,10 +602,20 @@ func saveextras(tx *sql.Tx, h *Honk) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if m := h.Mentions; len(m) > 0 {
|
||||
j, err := jsonify(m)
|
||||
if err == nil {
|
||||
_, err = tx.Stmt(stmtSaveMeta).Exec(h.ID, "mentions", j)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("error saving mentions: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteextras(tx *sql.Tx, honkid int64) error {
|
||||
func deleteextras(tx *sql.Tx, honkid int64, everything bool) error {
|
||||
_, err := tx.Stmt(stmtDeleteDonks).Exec(honkid)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -592,7 +624,11 @@ func deleteextras(tx *sql.Tx, honkid int64) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Stmt(stmtDeleteMeta).Exec(honkid, "oldrev")
|
||||
if everything {
|
||||
_, err = tx.Stmt(stmtDeleteAllMeta).Exec(honkid)
|
||||
} else {
|
||||
_, err = tx.Stmt(stmtDeleteSomeMeta).Exec(honkid)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -691,8 +727,10 @@ var stmtAddDoover, stmtGetDoovers, stmtLoadDoover, stmtZapDoover, stmtOneHonker
|
|||
var stmtUntagged, stmtDeleteHonk, stmtDeleteDonks, stmtDeleteOnts, stmtSaveZonker *sql.Stmt
|
||||
var stmtGetZonkers, stmtRecentHonkers, stmtGetXonker, stmtSaveXonker, stmtDeleteXonker *sql.Stmt
|
||||
var stmtAllOnts, stmtSaveOnt, stmtUpdateFlags, stmtClearFlags *sql.Stmt
|
||||
var stmtHonksForUserFirstClass, stmtSaveMeta, stmtDeleteMeta, stmtUpdateHonk *sql.Stmt
|
||||
var stmtHonksForUserFirstClass *sql.Stmt
|
||||
var stmtSaveMeta, stmtDeleteAllMeta, stmtDeleteSomeMeta, stmtUpdateHonk *sql.Stmt
|
||||
var stmtHonksISaved, stmtGetFilters, stmtSaveFilter, stmtDeleteFilter *sql.Stmt
|
||||
var stmtGetTracks *sql.Stmt
|
||||
|
||||
func preparetodie(db *sql.DB, s string) *sql.Stmt {
|
||||
stmt, err := db.Prepare(s)
|
||||
|
@ -703,10 +741,10 @@ func preparetodie(db *sql.DB, s string) *sql.Stmt {
|
|||
}
|
||||
|
||||
func prepareStatements(db *sql.DB) {
|
||||
stmtHonkers = preparetodie(db, "select honkerid, userid, name, xid, flavor, combos from honkers where userid = ? and (flavor = 'presub' or flavor = 'sub' or flavor = 'peep' or flavor = 'unsub') order by name")
|
||||
stmtSaveHonker = preparetodie(db, "insert into honkers (userid, name, xid, flavor, combos, owner) values (?, ?, ?, ?, ?, ?)")
|
||||
stmtHonkers = preparetodie(db, "select honkerid, userid, name, xid, flavor, combos, meta from honkers where userid = ? and (flavor = 'presub' or flavor = 'sub' or flavor = 'peep' or flavor = 'unsub') order by name")
|
||||
stmtSaveHonker = preparetodie(db, "insert into honkers (userid, name, xid, flavor, combos, owner, meta) values (?, ?, ?, ?, ?, ?, ?)")
|
||||
stmtUpdateFlavor = preparetodie(db, "update honkers set flavor = ? where userid = ? and xid = ? and name = ? and flavor = ?")
|
||||
stmtUpdateHonker = preparetodie(db, "update honkers set name = ?, combos = ? where honkerid = ? and userid = ?")
|
||||
stmtUpdateHonker = preparetodie(db, "update honkers set name = ?, combos = ?, meta = ? where honkerid = ? and userid = ?")
|
||||
stmtOneHonker = preparetodie(db, "select xid from honkers where name = ? and userid = ?")
|
||||
stmtDubbers = preparetodie(db, "select honkerid, userid, name, xid, flavor from honkers where userid = ? and flavor = 'dub'")
|
||||
stmtNamedDubbers = preparetodie(db, "select honkerid, userid, name, xid, flavor from honkers where userid = ? and name = ? and flavor = 'dub'")
|
||||
|
@ -729,12 +767,13 @@ func prepareStatements(db *sql.DB) {
|
|||
stmtHonksByHonker = preparetodie(db, selecthonks+"join honkers on (honkers.xid = honks.honker or honkers.xid = honks.oonker) where honks.honkid > ? and honks.userid = ? and honkers.name = ?"+butnotthose+limit)
|
||||
stmtHonksByXonker = preparetodie(db, selecthonks+" where honks.honkid > ? and honks.userid = ? and (honker = ? or oonker = ?)"+butnotthose+limit)
|
||||
stmtHonksByCombo = preparetodie(db, selecthonks+" where honks.honkid > ? and honks.userid = ? and honks.honker in (select xid from honkers where honkers.userid = ? and honkers.combos like ?) "+butnotthose+" union "+selecthonks+"join onts on honks.honkid = onts.honkid where honks.honkid > ? and honks.userid = ? and onts.ontology in (select xid from honkers where combos like ?)"+butnotthose+limit)
|
||||
stmtHonksBySearch = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and (? = 0 or xid like ?) and (? = 0 or honks.honker = ? or honks.oonker = ?) and noise like ?"+butnotthose+limit)
|
||||
stmtHonksBySearch = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and (? = 0 or xid like ?) and (? = 0 or honks.honker = ? or honks.oonker = ?) and noise like ? and (? = 0 or noise not like ?)"+butnotthose+limit)
|
||||
stmtHonksByConvoy = preparetodie(db, selecthonks+"where honks.honkid > ? and (honks.userid = ? or (? = -1 and whofore = 2)) and convoy = ?"+limit)
|
||||
stmtHonksByOntology = preparetodie(db, selecthonks+"join onts on honks.honkid = onts.honkid where honks.honkid > ? and onts.ontology = ? and (honks.userid = ? or (? = -1 and honks.whofore = 2))"+limit)
|
||||
|
||||
stmtSaveMeta = preparetodie(db, "insert into honkmeta (honkid, genus, json) values (?, ?, ?)")
|
||||
stmtDeleteMeta = preparetodie(db, "delete from honkmeta where honkid = ? and genus <> ?")
|
||||
stmtDeleteAllMeta = preparetodie(db, "delete from honkmeta where honkid = ?")
|
||||
stmtDeleteSomeMeta = preparetodie(db, "delete from honkmeta where honkid = ? and genus not in ('oldrev')")
|
||||
stmtSaveHonk = preparetodie(db, "insert into honks (userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
stmtDeleteHonk = preparetodie(db, "delete from honks where honkid = ?")
|
||||
stmtUpdateHonk = preparetodie(db, "update honks set precis = ?, noise = ?, format = ?, whofore = ?, dt = ? where honkid = ?")
|
||||
|
@ -760,8 +799,8 @@ func prepareStatements(db *sql.DB) {
|
|||
stmtGetZonkers = preparetodie(db, "select zonkerid, name, wherefore from zonkers where userid = ? and wherefore <> 'zonk'")
|
||||
stmtSaveZonker = preparetodie(db, "insert into zonkers (userid, name, wherefore) values (?, ?, ?)")
|
||||
stmtGetXonker = preparetodie(db, "select info from xonkers where name = ? and flavor = ?")
|
||||
stmtSaveXonker = preparetodie(db, "insert into xonkers (name, info, flavor) values (?, ?, ?)")
|
||||
stmtDeleteXonker = preparetodie(db, "delete from xonkers where name = ? and flavor = ?")
|
||||
stmtSaveXonker = preparetodie(db, "insert into xonkers (name, info, flavor, dt) values (?, ?, ?, ?)")
|
||||
stmtDeleteXonker = preparetodie(db, "delete from xonkers where name = ? and flavor = ? and dt < ?")
|
||||
stmtRecentHonkers = preparetodie(db, "select distinct(honker) from honks where userid = ? and honker not in (select xid from honkers where userid = ? and flavor = 'sub') order by honkid desc limit 100")
|
||||
stmtUpdateFlags = preparetodie(db, "update honks set flags = flags | ? where honkid = ?")
|
||||
stmtClearFlags = preparetodie(db, "update honks set flags = flags & ~ ? where honkid = ?")
|
||||
|
@ -769,4 +808,5 @@ func prepareStatements(db *sql.DB) {
|
|||
stmtGetFilters = preparetodie(db, "select hfcsid, json from hfcs where userid = ?")
|
||||
stmtSaveFilter = preparetodie(db, "insert into hfcs (userid, json) values (?, ?)")
|
||||
stmtDeleteFilter = preparetodie(db, "delete from hfcs where userid = ? and hfcsid = ?")
|
||||
stmtGetTracks = preparetodie(db, "select fetches from tracks where xid = ?")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,38 @@
|
|||
changelog
|
||||
|
||||
-- next
|
||||
=== next
|
||||
|
||||
+ Configurable avatar colors.
|
||||
|
||||
+ Optional pleroma color scheme for the home sick...
|
||||
|
||||
+ Rebalance colors slightly. Looks a little fresher now?
|
||||
|
||||
+ Add unplug command for servers that have dropped off the net.
|
||||
|
||||
+ Add notes field to honkers to document their downfall.
|
||||
|
||||
+ Add notes field to filters for record keeping.
|
||||
|
||||
+ Negated search -terms.
|
||||
|
||||
+ A raw sendactivity API action for the bold.
|
||||
|
||||
+ More flexible meme names.
|
||||
|
||||
=== 0.8.5 Turnkey Blaster
|
||||
|
||||
+ Codenames in changelog.
|
||||
|
||||
+ Fix some bugs that may have interfered with federation.
|
||||
|
||||
+ Add some re: re: re: to replies.
|
||||
|
||||
+ Set an avatar. If you must.
|
||||
|
||||
+ Try a little harder to recover from httpsig failures.
|
||||
|
||||
+ Add cite tag for block quote attributions.
|
||||
|
||||
+ deluser command.
|
||||
|
||||
|
@ -10,17 +42,17 @@ changelog
|
|||
|
||||
+ Can never seem to version the changelog correctly.
|
||||
|
||||
-- 0.8.4
|
||||
=== 0.8.4
|
||||
|
||||
+ Fix bug preventing import of keys
|
||||
|
||||
+ Option to switch map links to Apple.
|
||||
|
||||
-- 0.8.3
|
||||
=== 0.8.3
|
||||
|
||||
- mistag.
|
||||
|
||||
-- 0.8.2
|
||||
=== 0.8.2 Game Warden
|
||||
|
||||
++ Import command to preserve those embarssassing old posts from Twitter.
|
||||
|
||||
|
@ -36,7 +68,7 @@ changelog
|
|||
|
||||
+ "Bug" fixes.
|
||||
|
||||
-- 0.8.1
|
||||
=== 0.8.1
|
||||
|
||||
++ Make it easier to upgrade by decoupling data dir from ".".
|
||||
|
||||
|
@ -48,7 +80,7 @@ changelog
|
|||
Syntax highlighting for code blocks.
|
||||
Something resembling an actual manual.
|
||||
|
||||
-- 0.8.0
|
||||
=== 0.8.0 Ordinary Octology
|
||||
|
||||
+++ Add Honk Filtering and Censorship System (HFCS).
|
||||
|
||||
|
@ -103,7 +135,7 @@ changelog
|
|||
- Sometimes the cached state of the @me feed becomes unsynced.
|
||||
Acked status may display incorrectly.
|
||||
|
||||
-- 0.7.7
|
||||
=== 0.7.7 More 7 Than Ever
|
||||
|
||||
+ Add another retry to workaround pixelfed's general unreliability.
|
||||
|
||||
|
@ -115,11 +147,11 @@ changelog
|
|||
|
||||
+ Increase max thread retrieval depth to 10.
|
||||
|
||||
-- 0.7.6
|
||||
=== 0.7.6
|
||||
|
||||
+ Fix a bug where upgrades would not complete in one step.
|
||||
|
||||
-- 0.7.5
|
||||
=== 0.7.5
|
||||
|
||||
+ Fix a bug (introdcued 0.7.4) preventing new user creation from working.
|
||||
|
||||
|
@ -131,7 +163,7 @@ changelog
|
|||
|
||||
+ What may be considered UI improvements.
|
||||
|
||||
-- 0.7.4
|
||||
=== 0.7.4
|
||||
|
||||
+ Ever more bug fixes.
|
||||
|
||||
|
@ -147,19 +179,19 @@ changelog
|
|||
|
||||
+ webp image transcoding.
|
||||
|
||||
-- 0.7.3
|
||||
=== 0.7.3
|
||||
|
||||
+ Better fedicompat so bonks are visible to pleroma followers.
|
||||
|
||||
-- 0.7.2
|
||||
=== 0.7.2
|
||||
|
||||
+ Add the funzone. Minor other UI tweaks.
|
||||
|
||||
-- 0.7.1
|
||||
=== 0.7.1
|
||||
|
||||
+ Fix bug preventing unfollow from working.
|
||||
|
||||
-- 0.7.0
|
||||
=== 0.7.0 Father Mother Maiden Crone Honker Bonker Zonker
|
||||
|
||||
+++ Auto fetching and inlining of hoots.
|
||||
|
||||
|
@ -189,6 +221,12 @@ changelog
|
|||
|
||||
+ Add max-width for video tag.
|
||||
|
||||
-- 0.6.0 and prior
|
||||
=== 0.6.0 Sixy Delights
|
||||
|
||||
All records from this time of primitive development have been lost.
|
||||
Most records from this time of primitive development have been lost.
|
||||
|
||||
=== 0.5.0 Halfway to Heaven
|
||||
|
||||
=== 0.4.0 Fore Score
|
||||
|
||||
=== 0.3.0 Valorous Varaha
|
||||
|
|
|
@ -28,6 +28,12 @@ It is accessed via the
|
|||
.Pa filters
|
||||
menu item.
|
||||
.Pp
|
||||
Each filter has an optional
|
||||
.Ar name
|
||||
and
|
||||
.Ar notes
|
||||
for user defined purposes.
|
||||
.Pp
|
||||
The following match types are possible.
|
||||
All nonempty criteria must match.
|
||||
.Bl -tag -width include-audience
|
||||
|
|
26
docs/honk.1
26
docs/honk.1
|
@ -43,15 +43,18 @@ The
|
|||
field is required.
|
||||
Either of two forms are accepted, the user's handle (or webfinger) or their
|
||||
ActivityPub actor URL.
|
||||
The
|
||||
.Ar name
|
||||
field is optional and will be automatically inferred.
|
||||
Examples:
|
||||
.Pp
|
||||
.Dl @user@example.social
|
||||
.Dl https://example.social/users/user
|
||||
.Pp
|
||||
The
|
||||
.Ar name
|
||||
field is optional and will be automatically inferred.
|
||||
The
|
||||
.Ar notes
|
||||
field is reserved for user remarks.
|
||||
Fellow honkers may be added to one or more
|
||||
.Ic combos
|
||||
.Ar combos
|
||||
to suit one's organizational preferences.
|
||||
These are accessed via the
|
||||
.Pa combos
|
||||
|
@ -143,11 +146,14 @@ The following keywords are supported:
|
|||
Substring match on the post domain name.
|
||||
.It honker
|
||||
Exact match, either AP actor or honker nickname.
|
||||
.It -
|
||||
Negate term.
|
||||
.El
|
||||
.Pp
|
||||
Example:
|
||||
.Dl honker:goose big moose
|
||||
This query will find honks by the goose about the big moose.
|
||||
.Dl honker:goose big moose -footloose
|
||||
This query will find honks by the goose about the big moose, but excluding
|
||||
those about footloose.
|
||||
.Ss Filtering
|
||||
Sometimes other users of the federation can get unruly.
|
||||
The honk filtering and censorship system,
|
||||
|
@ -164,6 +170,12 @@ It also allows the import of external objects via URL, either individual
|
|||
posts or actor URLs, in which case their recent outbox is imported.
|
||||
.Ss Account
|
||||
It's all about you.
|
||||
An avatar may be selected from the
|
||||
.Pa funzone
|
||||
by adding
|
||||
.Dq avatar: filename.png
|
||||
to one's profile info.
|
||||
If truly necessary.
|
||||
.Pp
|
||||
Some options to customize the site appearance:
|
||||
.Bl -tag -width skinny
|
||||
|
|
14
docs/honk.3
14
docs/honk.3
|
@ -109,6 +109,20 @@ If there are no results, wait this many seconds for something to appear.
|
|||
.El
|
||||
.Pp
|
||||
The result will be returned as json.
|
||||
.Ss sendactivity
|
||||
Send anything.
|
||||
No limits, no error checking.
|
||||
.Bl -tag -width public
|
||||
.It Fa rcpt
|
||||
An actor to deliver the message to to.
|
||||
May be specified more than once.
|
||||
An inbox may be specified directly by prefixing with %.
|
||||
.It Fa msg
|
||||
The message.
|
||||
It should be a valid json activity, but yolo.
|
||||
.It Fa public
|
||||
Set to 1 to use shared inboxes for delivery.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Refer to the sample code in the
|
||||
.Pa toys
|
||||
|
|
15
docs/honk.8
15
docs/honk.8
|
@ -100,6 +100,8 @@ Displayed on the home page.
|
|||
Displayed on the about page.
|
||||
.It login
|
||||
Displayed about the login form.
|
||||
.It avatar colors
|
||||
Four 32-bit hex colors (RGBA).
|
||||
.El
|
||||
.Pp
|
||||
.Ss User Admin
|
||||
|
@ -137,6 +139,12 @@ file which is important to backup and restore.
|
|||
The current version of the honk binary may be printed with the
|
||||
.Ic version
|
||||
command.
|
||||
.Ss unplug
|
||||
Sometimes servers simply disappear, resulting in many errors trying to deliver
|
||||
undeliverable messages.
|
||||
Running
|
||||
.Ic unplug Ar hostname
|
||||
will delete all subscriptions and pending deliveries.
|
||||
.Ss Security
|
||||
.Nm
|
||||
is not currently hardened against SSRF, server side request forgery.
|
||||
|
@ -147,6 +155,7 @@ Debug mode may be enabled or disabled by running
|
|||
.Ic debug Ar on|off .
|
||||
In debug mode, secure cookies are disabled and templates are reloaded
|
||||
every request.
|
||||
Debug mode is really more useful for development, not debugging production.
|
||||
.Ss Import
|
||||
Data may be imported and converted from other services using the
|
||||
.Ic import
|
||||
|
@ -197,6 +206,12 @@ honk-v98> ./honk -datadir ../honkdata admin
|
|||
honk-v98> date; ./honk -datadir ../honkdata >> log 2>&1
|
||||
.Ed
|
||||
.Pp
|
||||
The views directory includes a sample pleroma.css to change color scheme.
|
||||
.Bd -literal -offset indent
|
||||
honk-v98> mkdir ../honkdata/views
|
||||
honk-v98> cp views/pleroma.css ../honkdata/views/local.css
|
||||
.Ed
|
||||
.Pp
|
||||
Upgrade to the next version.
|
||||
Clean things up a bit.
|
||||
.Bd -literal -offset indent
|
||||
|
|
|
@ -274,15 +274,6 @@ a.In { }
|
|||
font-weight: normal;
|
||||
font-family: monospace; }
|
||||
|
||||
/* Tooltip support. */
|
||||
|
||||
h1.Sh, h2.Ss { position: relative; }
|
||||
.An, .Ar, .Cd, .Cm, .Dv, .Em, .Er, .Ev, .Fa, .Fd, .Fl, .Fn, .Ft,
|
||||
.Ic, code.In, .Lb, .Lk, .Ms, .Mt, .Nd, code.Nm, .Pa, .Rs,
|
||||
.St, .Sx, .Sy, .Va, .Vt, .Xr {
|
||||
display: inline-block;
|
||||
position: relative; }
|
||||
|
||||
/* Overrides to avoid excessive margins on small devices. */
|
||||
|
||||
@media (max-width: 37.5em) {
|
||||
|
|
70
fun.go
70
fun.go
|
@ -28,6 +28,7 @@ import (
|
|||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
"humungus.tedunangst.com/r/webs/cache"
|
||||
|
@ -60,17 +61,18 @@ func reverbolate(userid int64, honks []*Honk) {
|
|||
if !h.Public {
|
||||
h.Style += " limited"
|
||||
}
|
||||
translate(h, false)
|
||||
if h.Whofore == 2 || h.Whofore == 3 {
|
||||
h.URL = h.XID
|
||||
if h.What != "bonked" {
|
||||
translate(h)
|
||||
local := false
|
||||
if (h.Whofore == 2 || h.Whofore == 3) && h.What != "bonked" {
|
||||
local = true
|
||||
}
|
||||
if local {
|
||||
h.Noise = re_memes.ReplaceAllString(h.Noise, "")
|
||||
h.Noise = mentionize(h.Noise)
|
||||
h.Noise = ontologize(h.Noise)
|
||||
}
|
||||
h.Username, h.Handle = handles(h.Honker)
|
||||
} else {
|
||||
_, h.Handle = handles(h.Honker)
|
||||
if !local {
|
||||
short := shortname(userid, h.Honker)
|
||||
if short != "" {
|
||||
h.Username = short
|
||||
|
@ -80,10 +82,10 @@ func reverbolate(userid int64, honks []*Honk) {
|
|||
h.Username = h.Username[:20] + ".."
|
||||
}
|
||||
}
|
||||
}
|
||||
if h.URL == "" {
|
||||
h.URL = h.XID
|
||||
}
|
||||
}
|
||||
if h.Oonker != "" {
|
||||
_, h.Oondle = handles(h.Oonker)
|
||||
}
|
||||
|
@ -129,6 +131,13 @@ func reverbolate(userid int64, honks []*Honk) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if local {
|
||||
var emu Emu
|
||||
emucache.Get(e, &emu)
|
||||
if emu.ID != "" {
|
||||
return fmt.Sprintf(`<img class="emu" title="%s" src="%s">`, emu.Name, emu.ID)
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
h.Precis = re_emus.ReplaceAllStringFunc(h.Precis, emuxifier)
|
||||
|
@ -189,7 +198,7 @@ func imaginate(honk *Honk) {
|
|||
htf.String(honk.Noise)
|
||||
}
|
||||
|
||||
func translate(honk *Honk, redoimages bool) {
|
||||
func translate(honk *Honk) {
|
||||
if honk.Format == "html" {
|
||||
return
|
||||
}
|
||||
|
@ -210,8 +219,9 @@ func translate(honk *Honk, redoimages bool) {
|
|||
noise = markitzero(noise)
|
||||
honk.Noise = noise
|
||||
honk.Onts = oneofakind(ontologies(honk.Noise))
|
||||
}
|
||||
|
||||
if redoimages {
|
||||
func redoimages(honk *Honk) {
|
||||
zap := make(map[string]bool)
|
||||
{
|
||||
var htf htfilter.Filter
|
||||
|
@ -235,7 +245,6 @@ func translate(honk *Honk, redoimages bool) {
|
|||
honk.Noise = ontologize(mentionize(honk.Noise))
|
||||
honk.Noise = strings.Replace(honk.Noise, "<a href=", "<a class=\"mention u-url\" href=", -1)
|
||||
}
|
||||
}
|
||||
|
||||
func xcelerate(b []byte) string {
|
||||
letters := "BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz1234567891234567891234"
|
||||
|
@ -276,11 +285,6 @@ func ontologies(s string) []string {
|
|||
return m[:j]
|
||||
}
|
||||
|
||||
type Mention struct {
|
||||
who string
|
||||
where string
|
||||
}
|
||||
|
||||
var re_mentions = regexp.MustCompile(`@[[:alnum:]._-]+@[[:alnum:].-]*[[:alnum:]]`)
|
||||
var re_urltions = regexp.MustCompile(`@https://\S+`)
|
||||
|
||||
|
@ -306,12 +310,12 @@ func bunchofgrapes(s string) []Mention {
|
|||
for i := range m {
|
||||
where := gofish(m[i])
|
||||
if where != "" {
|
||||
mentions = append(mentions, Mention{who: m[i], where: where})
|
||||
mentions = append(mentions, Mention{Who: m[i], Where: where})
|
||||
}
|
||||
}
|
||||
m = re_urltions.FindAllString(s, -1)
|
||||
for i := range m {
|
||||
mentions = append(mentions, Mention{who: m[i][1:], where: m[i][1:]})
|
||||
mentions = append(mentions, Mention{Who: m[i][1:], Where: m[i][1:]})
|
||||
}
|
||||
return mentions
|
||||
}
|
||||
|
@ -323,23 +327,33 @@ type Emu struct {
|
|||
|
||||
var re_emus = regexp.MustCompile(`:[[:alnum:]_-]+:`)
|
||||
|
||||
var emucache = cache.New(cache.Options{Filler: func(ename string) (Emu, bool) {
|
||||
fname := ename[1 : len(ename)-1]
|
||||
_, err := os.Stat(dataDir + "/emus/" + fname + ".png")
|
||||
if err != nil {
|
||||
return Emu{Name: ename, ID: ""}, true
|
||||
}
|
||||
url := fmt.Sprintf("https://%s/emu/%s.png", serverName, fname)
|
||||
return Emu{ID: url, Name: ename}, true
|
||||
}, Duration: 10 * time.Second})
|
||||
|
||||
func herdofemus(noise string) []Emu {
|
||||
m := re_emus.FindAllString(noise, -1)
|
||||
m = oneofakind(m)
|
||||
var emus []Emu
|
||||
for _, e := range m {
|
||||
fname := e[1 : len(e)-1]
|
||||
_, err := os.Stat("emus/" + fname + ".png")
|
||||
if err != nil {
|
||||
var emu Emu
|
||||
emucache.Get(e, &emu)
|
||||
if emu.ID == "" {
|
||||
continue
|
||||
}
|
||||
url := fmt.Sprintf("https://%s/emu/%s.png", serverName, fname)
|
||||
emus = append(emus, Emu{ID: url, Name: e})
|
||||
emus = append(emus, emu)
|
||||
}
|
||||
return emus
|
||||
}
|
||||
|
||||
var re_memes = regexp.MustCompile("meme: ?([[:alnum:]_.-]+)")
|
||||
var re_memes = regexp.MustCompile("meme: ?([^\n]+)")
|
||||
var re_avatar = regexp.MustCompile("avatar: ?([^\n]+)")
|
||||
|
||||
func memetize(honk *Honk) {
|
||||
repl := func(x string) string {
|
||||
|
@ -377,7 +391,7 @@ func memetize(honk *Honk) {
|
|||
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 {
|
||||
nonstop := true
|
||||
|
@ -392,7 +406,7 @@ func quickrename(s string, userid int64) string {
|
|||
prefix += "@"
|
||||
m = m[1:]
|
||||
tail := ""
|
||||
if m[len(m)-1] == ' ' || m[len(m)-1] == '\n' {
|
||||
if last := m[len(m)-1]; last == ' ' || last == '\n' || last == '.' {
|
||||
tail = m[len(m)-1:]
|
||||
m = m[:len(m)-1]
|
||||
}
|
||||
|
@ -613,6 +627,12 @@ func zaggy(keyname string) *rsa.PublicKey {
|
|||
return key
|
||||
}
|
||||
|
||||
func savingthrow(keyname string) {
|
||||
when := time.Now().UTC().Add(-30 * time.Minute).Format(dbtimeformat)
|
||||
stmtDeleteXonker.Exec(keyname, "pubkey", when)
|
||||
zaggies.Clear(keyname)
|
||||
}
|
||||
|
||||
func keymatch(keyname string, actor string) string {
|
||||
hash := strings.IndexByte(keyname, '#')
|
||||
if hash == -1 {
|
||||
|
|
52
hfcs.go
52
hfcs.go
|
@ -44,6 +44,7 @@ type Filter struct {
|
|||
re_rewrite *regexp.Regexp
|
||||
Replace string `json:",omitempty"`
|
||||
Expiration time.Time
|
||||
Notes string
|
||||
}
|
||||
|
||||
type filtType uint
|
||||
|
@ -168,15 +169,24 @@ func getfilters(userid int64, scope filtType) []*Filter {
|
|||
return nil
|
||||
}
|
||||
|
||||
func rejectorigin(userid int64, origin string) bool {
|
||||
func rejectorigin(userid int64, origin string, isannounce bool) bool {
|
||||
if o := originate(origin); o != "" {
|
||||
origin = o
|
||||
}
|
||||
filts := getfilters(userid, filtReject)
|
||||
for _, f := range filts {
|
||||
if f.IsAnnounce || f.Text != "" {
|
||||
if f.Text != "" {
|
||||
continue
|
||||
}
|
||||
if f.IsAnnounce {
|
||||
if !isannounce {
|
||||
continue
|
||||
}
|
||||
if f.AnnounceOf == origin {
|
||||
log.Printf("rejecting announce: %s", origin)
|
||||
return true
|
||||
}
|
||||
}
|
||||
if f.Actor == origin {
|
||||
log.Printf("rejecting origin: %s", origin)
|
||||
return true
|
||||
|
@ -204,7 +214,7 @@ func stealthmode(userid int64, r *http.Request) bool {
|
|||
agent := r.UserAgent()
|
||||
agent = originate(agent)
|
||||
if agent != "" {
|
||||
fake := rejectorigin(userid, agent)
|
||||
fake := rejectorigin(userid, agent, false)
|
||||
if fake {
|
||||
log.Printf("faking 404 for %s", agent)
|
||||
return true
|
||||
|
@ -214,21 +224,29 @@ func stealthmode(userid int64, r *http.Request) bool {
|
|||
}
|
||||
|
||||
func matchfilter(h *Honk, f *Filter) bool {
|
||||
return matchfilterX(h, f) != ""
|
||||
}
|
||||
|
||||
func matchfilterX(h *Honk, f *Filter) string {
|
||||
rv := ""
|
||||
match := true
|
||||
if match && f.Actor != "" {
|
||||
match = false
|
||||
if f.Actor == h.Honker || f.Actor == h.Oonker {
|
||||
match = true
|
||||
rv = f.Actor
|
||||
}
|
||||
if !match && (f.Actor == originate(h.Honker) ||
|
||||
f.Actor == originate(h.Oonker) ||
|
||||
f.Actor == originate(h.XID)) {
|
||||
match = true
|
||||
rv = f.Actor
|
||||
}
|
||||
if !match && f.IncludeAudience {
|
||||
for _, a := range h.Audience {
|
||||
if f.Actor == a || f.Actor == originate(a) {
|
||||
match = true
|
||||
rv = f.Actor
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -239,23 +257,33 @@ func matchfilter(h *Honk, f *Filter) bool {
|
|||
if (f.AnnounceOf == "" && h.Oonker != "") || f.AnnounceOf == h.Oonker ||
|
||||
f.AnnounceOf == originate(h.Oonker) {
|
||||
match = true
|
||||
rv += " announce"
|
||||
}
|
||||
}
|
||||
if match && f.Text != "" {
|
||||
match = false
|
||||
re := f.re_text
|
||||
if re.MatchString(h.Noise) || re.MatchString(h.Precis) {
|
||||
match = true
|
||||
m := re.FindString(h.Precis)
|
||||
if m == "" {
|
||||
m = re.FindString(h.Noise)
|
||||
}
|
||||
if !match {
|
||||
if m == "" {
|
||||
for _, d := range h.Donks {
|
||||
if re.MatchString(d.Desc) {
|
||||
m = re.FindString(d.Desc)
|
||||
if m != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if m != "" {
|
||||
match = true
|
||||
rv = m
|
||||
}
|
||||
}
|
||||
if match {
|
||||
return rv
|
||||
}
|
||||
}
|
||||
return match
|
||||
return ""
|
||||
}
|
||||
|
||||
func rejectxonk(xonk *Honk) bool {
|
||||
|
@ -282,11 +310,7 @@ func skipMedia(xonk *Honk) bool {
|
|||
func unsee(userid int64, h *Honk) {
|
||||
filts := getfilters(userid, filtCollapse)
|
||||
for _, f := range filts {
|
||||
if matchfilter(h, f) {
|
||||
bad := f.Text
|
||||
if f.Actor != "" {
|
||||
bad = f.Actor
|
||||
}
|
||||
if bad := matchfilterX(h, f); bad != "" {
|
||||
if h.Precis == "" {
|
||||
h.Precis = bad
|
||||
}
|
||||
|
|
29
honk.go
29
honk.go
|
@ -88,6 +88,12 @@ type Honk struct {
|
|||
Onts []string
|
||||
Place *Place
|
||||
Time *Time
|
||||
Mentions []Mention
|
||||
}
|
||||
|
||||
type Mention struct {
|
||||
Who string
|
||||
Where string
|
||||
}
|
||||
|
||||
type OldRevision struct {
|
||||
|
@ -173,6 +179,11 @@ type Honker struct {
|
|||
Handle string
|
||||
Flavor string
|
||||
Combos []string
|
||||
Meta HonkerMeta
|
||||
}
|
||||
|
||||
type HonkerMeta struct {
|
||||
Notes string
|
||||
}
|
||||
|
||||
type SomeThing struct {
|
||||
|
@ -199,6 +210,13 @@ var loginMsg template.HTML
|
|||
func ElaborateUnitTests() {
|
||||
}
|
||||
|
||||
func unplugserver(hostname string) {
|
||||
db := opendatabase()
|
||||
xid := fmt.Sprintf("%%https://%s/%%", hostname)
|
||||
db.Exec("delete from honkers where xid like ? and flavor = 'dub'", xid)
|
||||
db.Exec("delete from doovers where rcpt like ?", xid)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&dataDir, "datadir", dataDir, "data directory")
|
||||
flag.StringVar(&viewDir, "viewdir", viewDir, "view directory")
|
||||
|
@ -244,9 +262,9 @@ func main() {
|
|||
}
|
||||
switch args[1] {
|
||||
case "on":
|
||||
updateconfig("debug", 1)
|
||||
setconfig("debug", 1)
|
||||
case "off":
|
||||
updateconfig("debug", 0)
|
||||
setconfig("debug", 0)
|
||||
default:
|
||||
log.Fatal("argument must be on or off")
|
||||
}
|
||||
|
@ -266,6 +284,13 @@ func main() {
|
|||
arg = args[1]
|
||||
}
|
||||
cleanupdb(arg)
|
||||
case "unplug":
|
||||
if len(args) < 2 {
|
||||
fmt.Printf("usage: honk unplug servername\n")
|
||||
return
|
||||
}
|
||||
name := args[1]
|
||||
unplugserver(name)
|
||||
case "ping":
|
||||
if len(args) < 3 {
|
||||
fmt.Printf("usage: honk ping from to\n")
|
||||
|
|
|
@ -28,7 +28,8 @@ var re_bolder = regexp.MustCompile(`(^|\W)\*\*((?s:.*?))\*\*($|\W)`)
|
|||
var re_italicer = regexp.MustCompile(`(^|\W)\*((?s:.*?))\*($|\W)`)
|
||||
var re_bigcoder = regexp.MustCompile("```(.*)\n?((?s:.*?))\n?```\n?")
|
||||
var re_coder = regexp.MustCompile("`([^`]*)`")
|
||||
var re_quoter = regexp.MustCompile(`(?m:^> (.*)\n?)`)
|
||||
var re_quoter = regexp.MustCompile(`(?m:^> (.*)(\n- ?(.*))?\n?)`)
|
||||
var re_reciter = regexp.MustCompile(`(<cite><a href=".*?">)https://twitter.com/([^/]+)/.*?(</a></cite>)`)
|
||||
var re_link = regexp.MustCompile(`.?.?https?://[^\s"]+[\w/)!]`)
|
||||
var re_zerolink = regexp.MustCompile(`\[([^]]*)\]\(([^)]*\)?)\)`)
|
||||
var re_imgfix = regexp.MustCompile(`<img ([^>]*)>`)
|
||||
|
@ -77,7 +78,8 @@ func markitzero(s string) string {
|
|||
s = re_zerolink.ReplaceAllString(s, `<a href="$2">$1</a>`)
|
||||
s = re_bolder.ReplaceAllString(s, "$1<b>$2</b>$3")
|
||||
s = re_italicer.ReplaceAllString(s, "$1<i>$2</i>$3")
|
||||
s = re_quoter.ReplaceAllString(s, "<blockquote>$1</blockquote><p>")
|
||||
s = re_quoter.ReplaceAllString(s, "<blockquote>$1<br><cite>$3</cite></blockquote><p>")
|
||||
s = re_reciter.ReplaceAllString(s, "$1$2$3")
|
||||
s = strings.Replace(s, "\n---\n", "<hr><p>", -1)
|
||||
|
||||
s = re_lister.ReplaceAllStringFunc(s, func(m string) string {
|
||||
|
@ -117,6 +119,7 @@ func markitzero(s string) string {
|
|||
// some final fixups
|
||||
s = strings.Replace(s, "\n", "<br>", -1)
|
||||
s = strings.Replace(s, "<br><blockquote>", "<blockquote>", -1)
|
||||
s = strings.Replace(s, "<br><cite></cite>", "", -1)
|
||||
s = strings.Replace(s, "<br><pre>", "<pre>", -1)
|
||||
s = strings.Replace(s, "<br><ul>", "<ul>", -1)
|
||||
s = strings.Replace(s, "<p><br>", "<p>", -1)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -106,3 +107,22 @@ para
|
|||
output := `hello<ul><li>a list<li>the list</ul><p>para<ul><li>singleton</ul><p>`
|
||||
doonezerotest(t, input, output)
|
||||
}
|
||||
|
||||
var benchData, simpleData string
|
||||
|
||||
func init() {
|
||||
benchData = strings.Repeat("hello there sir. It is a **fine** day for some testing!\n", 100)
|
||||
simpleData = strings.Repeat("just a few words\n", 100)
|
||||
}
|
||||
|
||||
func BenchmarkModerateSize(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
markitzero(benchData)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSimpleData(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
markitzero(simpleData)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ var sqlSchema = `
|
|||
create table honks (honkid integer primary key, userid integer, what text, honker text, xid text, rid text, dt text, url text, audience text, noise text, convoy text, whofore integer, format text, precis text, oonker text, flags integer);
|
||||
create table donks (honkid integer, fileid integer);
|
||||
create table filemeta (fileid integer primary key, xid text, name text, description text, url text, media text, local integer);
|
||||
create table honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, combos text, owner text);
|
||||
create table xonkers (xonkerid integer primary key, name text, info text, flavor text);
|
||||
create table honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, combos text, owner text, meta text);
|
||||
create table xonkers (xonkerid integer primary key, name text, info text, flavor text, dt text);
|
||||
create table zonkers (zonkerid integer primary key, userid integer, name text, wherefore text);
|
||||
create table doovers(dooverid integer primary key, dt text, tries integer, userid integer, rcpt text, msg blob);
|
||||
create table onts (ontology text, honkid integer);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
create table honks (honkid integer primary key, userid integer, what text, honker text, xid text, rid text, dt text, url text, audience text, noise text, convoy text, whofore integer, format text, precis text, oonker text, flags integer);
|
||||
create table donks (honkid integer, fileid integer);
|
||||
create table filemeta (fileid integer primary key, xid text, name text, description text, url text, media text, local integer);
|
||||
create table honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, combos text, owner text);
|
||||
create table xonkers (xonkerid integer primary key, name text, info text, flavor text);
|
||||
create table honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, combos text, owner text, meta text);
|
||||
create table xonkers (xonkerid integer primary key, name text, info text, flavor text, dt text);
|
||||
create table zonkers (zonkerid integer primary key, userid integer, name text, wherefore text);
|
||||
create table doovers(dooverid integer primary key, dt text, tries integer, userid integer, rcpt text, msg blob);
|
||||
create table onts (ontology text, honkid integer);
|
||||
|
|
|
@ -21,87 +21,9 @@ import (
|
|||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
// these lists are mostly (?) accurate
|
||||
var bigboldshitz = "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙"
|
||||
var lilboldshitz = "𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳"
|
||||
var moeboldshitz = "𝗔𝗕𝗖𝗗𝗘𝗙𝗚𝗛𝗜𝗝𝗞𝗟𝗠𝗡𝗢𝗣𝗤𝗥𝗦𝗧𝗨𝗩𝗪𝗫𝗬𝗭"
|
||||
var morboldshitz = "𝗮𝗯𝗰𝗱𝗲𝗳𝗴𝗵𝗶𝗷𝗸𝗹𝗺𝗻𝗼𝗽𝗾𝗿𝘀𝘁𝘂𝘃𝘄𝘅𝘆𝘇"
|
||||
var biggothshitz = "𝕬𝕭𝕮𝕯𝕰𝕱𝕲𝕳𝕴𝕵𝕶𝕷𝕸𝕹𝕺𝕻𝕼𝕽𝕾𝕿𝖀𝖁𝖂𝖃𝖄𝖅"
|
||||
var lilgothshitz = "𝖆𝖇𝖈𝖉𝖊𝖋𝖌𝖍𝖎𝖏𝖐𝖑𝖒𝖓𝖔𝖕𝖖𝖗𝖘𝖙𝖚𝖛𝖜𝖝𝖞𝖟"
|
||||
var moegothshitz = "𝔄𝔅𝕮𝔇𝔈𝔉𝔊𝕳ℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜𝖅"
|
||||
var morgothshitz = "𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷"
|
||||
var bigitalshitz = "𝑨𝑩𝑪𝑫𝑬𝑭𝑮𝑯𝑰𝑱𝑲𝑳𝑴𝑵𝑶𝑷𝑸𝑹𝑺𝑻𝑼𝑽𝑾𝑿𝒀𝒁"
|
||||
var lilitalshitz = "𝒂𝒃𝒄𝒅𝒆𝒇𝒈𝒉𝒊𝒋𝒌𝒍𝒎𝒏𝒐𝒑𝒒𝒓𝒔𝒕𝒖𝒗𝒘𝒙𝒚𝒛"
|
||||
var moeitalshitz = "𝘼𝘽𝘾𝘿𝙀𝙁𝙂𝙃𝙄𝙅𝙆𝙇𝙈𝙉𝙊𝙋𝙌𝙍𝙎𝙏𝙐𝙑𝙒𝙓𝙔𝙕"
|
||||
var moritalshitz = "𝙖𝙗𝙘𝙙𝙚𝙛𝙜𝙝𝙞𝙟𝙠𝙡𝙢𝙣𝙤𝙥𝙦𝙧𝙨𝙩𝙪𝙫𝙬𝙭𝙮𝙯"
|
||||
var bigbangshitz = "𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ"
|
||||
var lilbangshitz = "𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫"
|
||||
var bigwideshitz = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
var lilwideshitz = "abcdefghijklmnopqrstuvwxyz"
|
||||
var bigblokshitz = "🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉"
|
||||
var evenmoeshitz = "𝐴𝐵𝐶𝐷𝐸𝐹𝐺𝐻𝐼𝐽𝐾𝐿𝑀𝑁𝑂𝑃𝑄𝑅𝑆𝑇𝑈𝑉𝑊𝑋𝑌𝑍"
|
||||
var evenmorshitz = "𝒶𝒷𝒸𝒹𝑒𝒻𝓰𝒽𝒾𝒿𝓀𝓁𝓂𝓃𝓸𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏"
|
||||
|
||||
var re_alltheshitz = regexp.MustCompile(`([` +
|
||||
bigboldshitz + lilboldshitz +
|
||||
moeboldshitz + morboldshitz +
|
||||
biggothshitz + lilgothshitz +
|
||||
moegothshitz + morgothshitz +
|
||||
bigitalshitz + lilitalshitz +
|
||||
moeitalshitz + moritalshitz +
|
||||
bigbangshitz + lilbangshitz +
|
||||
bigwideshitz + lilwideshitz +
|
||||
evenmoeshitz + evenmorshitz +
|
||||
bigblokshitz +
|
||||
"][ '\ufe0f]?){3,}")
|
||||
|
||||
var allUppers = []string{bigboldshitz, moeboldshitz, biggothshitz, bigwideshitz, moegothshitz, bigitalshitz, moeitalshitz, bigbangshitz, bigblokshitz, evenmoeshitz}
|
||||
var allLowers = []string{lilboldshitz, morboldshitz, lilgothshitz, lilwideshitz, morgothshitz, lilitalshitz, moritalshitz, lilbangshitz, evenmorshitz}
|
||||
|
||||
var skinTones = "\U0001F3FB\U0001F3FC\U0001F3FD\U0001F3FE\U0001F3FF"
|
||||
var re_moredumb = regexp.MustCompile("[\U0001f44f\U0001f6a8\U000026a0][" + skinTones + "\ufe0f]*")
|
||||
|
||||
// this may not be especially fast
|
||||
func unpucker(s string) string {
|
||||
fixer := func(r string) string {
|
||||
x := make([]byte, len(r))
|
||||
xi := 0
|
||||
loop1:
|
||||
for _, c := range r {
|
||||
xi++
|
||||
if c == ' ' || c == '\'' {
|
||||
x[xi] = byte(c)
|
||||
continue
|
||||
}
|
||||
for _, set := range allUppers {
|
||||
i := 0
|
||||
for _, rr := range set {
|
||||
if rr == c {
|
||||
x[xi] = byte('A' + i)
|
||||
continue loop1
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
for _, set := range allLowers {
|
||||
i := 0
|
||||
for _, rr := range set {
|
||||
if rr == c {
|
||||
x[xi] = byte('a' + i)
|
||||
continue loop1
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
x[xi] = '.'
|
||||
}
|
||||
return string(x)
|
||||
}
|
||||
s = re_alltheshitz.ReplaceAllStringFunc(s, fixer)
|
||||
|
||||
return demoji(s)
|
||||
}
|
||||
|
||||
func demoji(s string) string {
|
||||
s = re_moredumb.ReplaceAllString(s, ".")
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
all: gettoken saytheday youvegothonks
|
||||
all: gettoken saytheday sprayandpray youvegothonks
|
||||
|
||||
gettoken: gettoken.go
|
||||
go build gettoken.go
|
||||
|
@ -7,5 +7,8 @@ gettoken: gettoken.go
|
|||
saytheday: saytheday.go
|
||||
go build saytheday.go
|
||||
|
||||
sprayandpray: sprayandpray.go
|
||||
go build sprayandpray.go
|
||||
|
||||
youvegothonks: youvegothonks.go
|
||||
go build youvegothonks.go
|
||||
|
|
|
@ -4,6 +4,8 @@ A little of this, a little of that.
|
|||
|
||||
gettoken.go - obtains an authorization token
|
||||
|
||||
saytheday.go - posts a new honk
|
||||
saytheday.go - posts a new honk that's a date based look and say sequence
|
||||
|
||||
sprayandpray.go - send an activity with no error checking and hope it works
|
||||
|
||||
youvegothonks.go - polls for new mesages
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
func sendmsg(server, token, msg, rcpt string) {
|
||||
form := make(url.Values)
|
||||
form.Add("token", token)
|
||||
form.Add("action", "sendactivity")
|
||||
form.Add("msg", msg)
|
||||
form.Add("rcpt", rcpt)
|
||||
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")
|
||||
resp, err := http.DefaultClient.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() {
|
||||
var server, token, msgfile, rcpt string
|
||||
flag.StringVar(&server, "server", server, "server to connnect")
|
||||
flag.StringVar(&token, "token", token, "auth token to use")
|
||||
flag.StringVar(&msgfile, "msgfile", token, "file with message to send")
|
||||
flag.StringVar(&rcpt, "rcpt", rcpt, "rcpt to send it to")
|
||||
flag.Parse()
|
||||
|
||||
if server == "" || token == "" || msgfile == "" || rcpt == "" {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
msg, err := ioutil.ReadFile(msgfile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
sendmsg(server, token, string(msg), rcpt)
|
||||
}
|
|
@ -62,4 +62,7 @@ func init() {
|
|||
C.unveil(nil, nil)
|
||||
Pledge("stdio rpath wpath cpath flock dns inet unix")
|
||||
})
|
||||
backendhooks = append(backendhooks, func() {
|
||||
Pledge("stdio unix")
|
||||
})
|
||||
}
|
||||
|
|
12
upgradedb.go
12
upgradedb.go
|
@ -24,7 +24,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var myVersion = 32
|
||||
var myVersion = 34
|
||||
|
||||
func doordie(db *sql.DB, s string, args ...interface{}) {
|
||||
_, err := db.Exec(s, args...)
|
||||
|
@ -356,6 +356,16 @@ func upgradedb() {
|
|||
doordie(db, "update config set value = 32 where key = 'dbversion'")
|
||||
fallthrough
|
||||
case 32:
|
||||
doordie(db, "alter table xonkers add column dt text")
|
||||
doordie(db, "update xonkers set dt = ?", time.Now().UTC().Format(dbtimeformat))
|
||||
doordie(db, "update config set value = 33 where key = 'dbversion'")
|
||||
fallthrough
|
||||
case 33:
|
||||
doordie(db, "alter table honkers add column meta text")
|
||||
doordie(db, "update honkers set meta = '{}'")
|
||||
doordie(db, "update config set value = 34 where key = 'dbversion'")
|
||||
fallthrough
|
||||
case 34:
|
||||
|
||||
default:
|
||||
log.Fatalf("can't upgrade unknown version %d", dbversion)
|
||||
|
|
7
util.go
7
util.go
|
@ -412,16 +412,11 @@ func getconfig(key string, value interface{}) error {
|
|||
|
||||
func setconfig(key string, val interface{}) error {
|
||||
db := opendatabase()
|
||||
db.Exec("delete from config where key = ?", key)
|
||||
_, err := db.Exec("insert into config (key, value) values (?, ?)", key, val)
|
||||
return err
|
||||
}
|
||||
|
||||
func updateconfig(key string, val interface{}) error {
|
||||
db := opendatabase()
|
||||
_, err := db.Exec("update config set value = ? where key = ?", val, key)
|
||||
return err
|
||||
}
|
||||
|
||||
func openListener() (net.Listener, error) {
|
||||
var listenAddr string
|
||||
err := getconfig("listenaddr", &listenAddr)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<form id="aboutform" action="/saveuser" method="POST">
|
||||
<input type="hidden" name="CSRF" value="{{ .UserCSRF }}">
|
||||
<p>about me:
|
||||
<p><textarea name="whatabout">{{ .User.About }}</textarea>
|
||||
<p><textarea name="whatabout">{{ .WhatAbout }}</textarea>
|
||||
<p><label class="button" for="skinny">skinny layout:</label>
|
||||
<input tabindex=1 type="checkbox" id="skinny" name="skinny" value="skinny" {{ if .User.Options.SkinnyCSS }}checked{{ end }}><span></span>
|
||||
<p><label class="button" for="maps">apple map links:</label>
|
||||
|
|
|
@ -9,6 +9,9 @@ Honk Filtering and Censorship System
|
|||
<h3>new filter</h3>
|
||||
<p><label for="name">filter name:</label><br>
|
||||
<input tabindex=1 type="text" name="name" value="" autocomplete=off>
|
||||
<p><label for="filtnotes">notes:</label><br>
|
||||
<textarea tabindex=1 name="filtnotes" height=4>
|
||||
</textarea>
|
||||
<hr>
|
||||
<h3>match</h3>
|
||||
<p><label for="actor">who or where:</label><br>
|
||||
|
@ -48,6 +51,7 @@ Honk Filtering and Censorship System
|
|||
{{ range .Filters }}
|
||||
<section class="honk">
|
||||
<p>Name: {{ .Name }}
|
||||
{{ with .Notes }}<p>Notes: {{ . }}{{ end }}
|
||||
<p>Date: {{ .Date.Format "2006-01-02" }}
|
||||
{{ with .Actor }}<p>Who: {{ . }}{{ end }} {{ with .IncludeAudience }} (inclusive) {{ end }}
|
||||
{{ with .Text }}<p>Text: {{ . }}{{ end }}
|
||||
|
|
|
@ -66,15 +66,15 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
|
|||
{{ range .Donks }}
|
||||
{{ if .Local }}
|
||||
{{ if eq .Media "text/plain" }}
|
||||
<p><a href="/d/{{ .XID }}">Attachment: {{ .Name }}</a> {{ .Desc }}
|
||||
<p><a href="/d/{{ .XID }}">Attachment: {{ .Name }}</a>{{ if not (eq .Desc .Name) }} {{ .Desc }}{{ end }}
|
||||
{{ else if eq .Media "application/pdf" }}
|
||||
<p><a href="/d/{{ .XID }}">Attachment: {{ .Name }}</a> {{ .Desc }}
|
||||
<p><a href="/d/{{ .XID }}">Attachment: {{ .Name }}</a>{{ if not (eq .Desc .Name) }} {{ .Desc }}{{ end }}
|
||||
{{ else }}
|
||||
<p><img src="/d/{{ .XID }}" title="{{ .Desc }}" alt="{{ .Desc }}">
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ if .XID }}
|
||||
<p><a href="{{ .URL }}" rel=noreferrer>External Attachment: {{ .Name }}</a>
|
||||
<p><a href="{{ .URL }}" rel=noreferrer>External Attachment: {{ .Name }}</a>{{ if not (eq .Desc .Name) }} {{ .Desc }}{{ end }}
|
||||
{{ else }}
|
||||
{{ if eq .Media "video/mp4" }}
|
||||
<p><video controls src="{{ .URL }}">{{ .Name }}</video>
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
<input tabindex=1 type="text" name="combos" value="" placeholder="optional">
|
||||
<p><span><label class=button for="peep">skip subscribe:
|
||||
<input tabindex=1 type="checkbox" id="peep" name="peep" value="peep"><span></span></label></span>
|
||||
<p><label for="notes">notes:</label><br>
|
||||
<textarea tabindex=1 name="notes">
|
||||
</textarea>
|
||||
<p><button tabindex=1 name="add honker" value="add honker">add honker</button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -42,6 +45,8 @@ function expandstuff() {
|
|||
<input type="hidden" name="CSRF" value="{{ $honkercsrf }}">
|
||||
<input type="hidden" name="honkerid" value="{{ .ID }}">
|
||||
<p>name: <input type="text" name="name" value="{{ .Name }}">
|
||||
<p><label for="notes">notes:</label><br>
|
||||
<textarea name="notes">{{ .Meta.Notes }}</textarea>
|
||||
<p>combos: <input type="text" name="combos" value="{{ range .Combos }}{{ . }} {{end}}">
|
||||
{{ if eq .Flavor "sub" }}
|
||||
<p>unsub: <input type="text" name="goodbye" placeholder="press F" value="" autocomplete=off>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
html {
|
||||
--bg-page: #1b2735;
|
||||
--bg-dark: #121a24;
|
||||
--fg: #b9b9ba;
|
||||
--hl: #d8a070;
|
||||
--fg-subtle: rgba(185, 185, 186, 0.5);
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
html {
|
||||
--bg-page: #305;
|
||||
--bg-page: #306;
|
||||
--bg-dark: #002;
|
||||
--fg: #dde;
|
||||
--fg-subtle: #aab;
|
||||
--fg: #dcf;
|
||||
--hl: #dcf;
|
||||
--fg-subtle: #a9c;
|
||||
--fg-limited: #a79;
|
||||
}
|
||||
|
||||
|
@ -23,6 +24,9 @@ blockquote {
|
|||
padding-left: 0.5em;
|
||||
border-left: 1px solid var(--fg-subtle);
|
||||
}
|
||||
blockquote cite {
|
||||
margin-left: 2em;
|
||||
}
|
||||
table {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
|
@ -73,7 +77,7 @@ header > details {
|
|||
header > details[open] {
|
||||
padding: 1em 1em 0em 1em;
|
||||
background: var(--bg-dark);
|
||||
border: 1px solid var(--fg);
|
||||
border: 1px solid var(--hl);
|
||||
margin-bottom: 1em;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
@ -99,9 +103,12 @@ main {
|
|||
margin: auto;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
hr {
|
||||
border-color: var(--hl);
|
||||
}
|
||||
.info {
|
||||
background: var(--bg-dark);
|
||||
border: 1px solid var(--fg);
|
||||
border: 1px solid var(--hl);
|
||||
margin-bottom: 1em;
|
||||
padding: 0em 1em 0em 1em;
|
||||
}
|
||||
|
@ -117,7 +124,7 @@ label.button, button, select {
|
|||
font-family: monospace;
|
||||
color: var(--fg);
|
||||
background: var(--bg-page);
|
||||
border: 1px solid var(--fg);
|
||||
border: 1px solid var(--hl);
|
||||
padding: 0.5em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
@ -140,11 +147,14 @@ textarea {
|
|||
background: var(--bg-page);
|
||||
color: var(--fg);
|
||||
width: 600px;
|
||||
height: 8em;
|
||||
height: 4em;
|
||||
margin-bottom: 0.5em;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
}
|
||||
textarea#honknoise {
|
||||
height: 10em;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
position: fixed;
|
||||
top: -9999px;
|
||||
|
@ -163,13 +173,13 @@ input[type=file] {
|
|||
}
|
||||
|
||||
.glow {
|
||||
box-shadow: 0px 0px 16px var(--fg);
|
||||
box-shadow: 0px 0px 16px var(--hl);
|
||||
}
|
||||
|
||||
.honk {
|
||||
margin: auto;
|
||||
background: var(--bg-dark);
|
||||
border: 1px solid var(--fg);
|
||||
border: 1px solid var(--hl);
|
||||
border-radius: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding-left: 1em;
|
||||
|
|
134
web.go
134
web.go
|
@ -48,6 +48,8 @@ var readviews *templates.Template
|
|||
var userSep = "u"
|
||||
var honkSep = "h"
|
||||
|
||||
var debugMode = false
|
||||
|
||||
func getuserstyle(u *login.UserInfo) template.CSS {
|
||||
if u == nil {
|
||||
return ""
|
||||
|
@ -223,8 +225,10 @@ func showrss(w http.ResponseWriter, r *http.Request) {
|
|||
modtime = honk.Date
|
||||
}
|
||||
}
|
||||
if !debugMode {
|
||||
w.Header().Set("Cache-Control", "max-age=300")
|
||||
w.Header().Set("Last-Modified", modtime.Format(http.TimeFormat))
|
||||
}
|
||||
|
||||
err := feed.Write(w)
|
||||
if err != nil {
|
||||
|
@ -330,6 +334,10 @@ func inbox(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
keyname, err := httpsig.VerifyRequest(r, payload, zaggy)
|
||||
if err != nil && keyname != "" {
|
||||
savingthrow(keyname)
|
||||
keyname, err = httpsig.VerifyRequest(r, payload, zaggy)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("inbox message failed signature for %s from %s", keyname, r.Header.Get("X-Forwarded-For"))
|
||||
if keyname != "" {
|
||||
|
@ -460,6 +468,10 @@ func serverinbox(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
keyname, err := httpsig.VerifyRequest(r, payload, zaggy)
|
||||
if err != nil && keyname != "" {
|
||||
savingthrow(keyname)
|
||||
keyname, err = httpsig.VerifyRequest(r, payload, zaggy)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("inbox message failed signature for %s from %s", keyname, r.Header.Get("X-Forwarded-For"))
|
||||
if keyname != "" {
|
||||
|
@ -866,7 +878,7 @@ func thelistingoftheontologies(w http.ResponseWriter, r *http.Request) {
|
|||
sort.Slice(onts, func(i, j int) bool {
|
||||
return onts[i].Name < onts[j].Name
|
||||
})
|
||||
if u == nil {
|
||||
if u == nil && !debugMode {
|
||||
w.Header().Set("Cache-Control", "max-age=300")
|
||||
}
|
||||
templinfo := getInfo(r)
|
||||
|
@ -882,6 +894,33 @@ type Track struct {
|
|||
who string
|
||||
}
|
||||
|
||||
func getbacktracks(xid string) []string {
|
||||
c := make(chan bool)
|
||||
dumptracks <- c
|
||||
<-c
|
||||
row := stmtGetTracks.QueryRow(xid)
|
||||
var rawtracks string
|
||||
err := row.Scan(&rawtracks)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
log.Printf("error scanning tracks: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var rcpts []string
|
||||
for _, f := range strings.Split(rawtracks, " ") {
|
||||
idx := strings.LastIndexByte(f, '#')
|
||||
if idx != -1 {
|
||||
f = f[:idx]
|
||||
}
|
||||
if !strings.HasPrefix(f, "https://") {
|
||||
f = fmt.Sprintf("%%https://%s/inbox", f)
|
||||
}
|
||||
rcpts = append(rcpts, f)
|
||||
}
|
||||
return rcpts
|
||||
}
|
||||
|
||||
func savetracks(tracks map[string][]string) {
|
||||
db := opendatabase()
|
||||
tx, err := db.Begin()
|
||||
|
@ -932,6 +971,7 @@ func savetracks(tracks map[string][]string) {
|
|||
}
|
||||
|
||||
var trackchan = make(chan Track)
|
||||
var dumptracks = make(chan chan bool)
|
||||
|
||||
func tracker() {
|
||||
timeout := 4 * time.Minute
|
||||
|
@ -947,6 +987,11 @@ func tracker() {
|
|||
tracks = make(map[string][]string)
|
||||
}
|
||||
sleeper.Reset(timeout)
|
||||
case c := <-dumptracks:
|
||||
if len(tracks) > 0 {
|
||||
savetracks(tracks)
|
||||
}
|
||||
c <- true
|
||||
case <-endoftheworld:
|
||||
if len(tracks) > 0 {
|
||||
savetracks(tracks)
|
||||
|
@ -1052,7 +1097,7 @@ func honkpage(w http.ResponseWriter, u *login.UserInfo, honks []*Honk, templinfo
|
|||
templinfo["TopHID"] = 0
|
||||
}
|
||||
}
|
||||
if u == nil {
|
||||
if u == nil && !debugMode {
|
||||
w.Header().Set("Cache-Control", "max-age=60")
|
||||
}
|
||||
err := readviews.Execute(w, "honkpage.html", templinfo)
|
||||
|
@ -1077,6 +1122,17 @@ func saveuser(w http.ResponseWriter, r *http.Request) {
|
|||
} else {
|
||||
options.MapLink = ""
|
||||
}
|
||||
if ava := re_avatar.FindString(whatabout); ava != "" {
|
||||
whatabout = re_avatar.ReplaceAllString(whatabout, "")
|
||||
ava = ava[7:]
|
||||
if ava[0] == ' ' {
|
||||
ava = ava[1:]
|
||||
}
|
||||
options.Avatar = fmt.Sprintf("https://%s/meme/%s", serverName, ava)
|
||||
} else {
|
||||
options.Avatar = ""
|
||||
}
|
||||
whatabout = strings.TrimSpace(whatabout)
|
||||
j, err := jsonify(options)
|
||||
if err == nil {
|
||||
_, err = db.Exec("update users set about = ?, options = ? where username = ?", whatabout, j, u.Username)
|
||||
|
@ -1383,8 +1439,9 @@ func submithonk(w http.ResponseWriter, r *http.Request, isAPI bool) {
|
|||
noise = strings.Replace(noise, "\r", "", -1)
|
||||
noise = quickrename(noise, userinfo.UserID)
|
||||
noise = hooterize(noise)
|
||||
honk.Mentions = bunchofgrapes(noise)
|
||||
honk.Noise = noise
|
||||
translate(honk, false)
|
||||
translate(honk)
|
||||
|
||||
var convoy string
|
||||
if rid != "" {
|
||||
|
@ -1406,6 +1463,12 @@ func submithonk(w http.ResponseWriter, r *http.Request, isAPI bool) {
|
|||
}
|
||||
}
|
||||
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: ")) {
|
||||
honk.Precis = "re: " + honk.Precis
|
||||
}
|
||||
}
|
||||
} else {
|
||||
honk.Audience = []string{thewholeworld}
|
||||
}
|
||||
|
@ -1516,14 +1579,6 @@ func submithonk(w http.ResponseWriter, r *http.Request, isAPI bool) {
|
|||
log.Printf("can't find file: %s", xid)
|
||||
}
|
||||
}
|
||||
herd := herdofemus(noise)
|
||||
for _, e := range herd {
|
||||
donk := savedonk(e.ID, e.Name, e.Name, "image/png", true)
|
||||
if donk != nil {
|
||||
donk.Name = e.Name
|
||||
honk.Donks = append(honk.Donks, donk)
|
||||
}
|
||||
}
|
||||
memetize(honk)
|
||||
imaginate(honk)
|
||||
|
||||
|
@ -1664,6 +1719,10 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
|
|||
combos = " " + combos + " "
|
||||
honkerid, _ := strconv.ParseInt(r.FormValue("honkerid"), 10, 0)
|
||||
|
||||
var meta HonkerMeta
|
||||
meta.Notes = strings.TrimSpace(r.FormValue("notes"))
|
||||
mj, _ := jsonify(&meta)
|
||||
|
||||
defer honkerinvalidator.Clear(u.UserID)
|
||||
|
||||
if honkerid > 0 {
|
||||
|
@ -1714,7 +1773,7 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
_, err := stmtUpdateHonker.Exec(name, combos, honkerid, u.UserID)
|
||||
_, err := stmtUpdateHonker.Exec(name, combos, mj, honkerid, u.UserID)
|
||||
if err != nil {
|
||||
log.Printf("update honker err: %s", err)
|
||||
return
|
||||
|
@ -1738,7 +1797,7 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
|
|||
if name == "" {
|
||||
name = url
|
||||
}
|
||||
_, err := stmtSaveHonker.Exec(u.UserID, name, url, flavor, combos, url)
|
||||
_, err := stmtSaveHonker.Exec(u.UserID, name, url, flavor, combos, url, mj)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
|
@ -1770,7 +1829,7 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
|
|||
if name == "" {
|
||||
name = info.Name
|
||||
}
|
||||
_, err = stmtSaveHonker.Exec(u.UserID, name, url, flavor, combos, info.Owner)
|
||||
_, err = stmtSaveHonker.Exec(u.UserID, name, url, flavor, combos, info.Owner, mj)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
|
@ -1827,6 +1886,7 @@ func savehfcs(w http.ResponseWriter, r *http.Request) {
|
|||
if dur := parseDuration(r.FormValue("filtduration")); dur > 0 {
|
||||
filt.Expiration = time.Now().UTC().Add(dur)
|
||||
}
|
||||
filt.Notes = strings.TrimSpace(r.FormValue("filtnotes"))
|
||||
|
||||
if filt.Actor == "" && filt.Text == "" && !filt.IsAnnounce {
|
||||
log.Printf("blank filter")
|
||||
|
@ -1853,6 +1913,11 @@ func accountpage(w http.ResponseWriter, r *http.Request) {
|
|||
templinfo["UserCSRF"] = login.GetCSRF("saveuser", r)
|
||||
templinfo["LogoutCSRF"] = login.GetCSRF("logout", r)
|
||||
templinfo["User"] = user
|
||||
about := user.About
|
||||
if ava := user.Options.Avatar; ava != "" {
|
||||
about += "\n\navatar: " + ava[strings.LastIndexByte(ava, '/')+1:]
|
||||
}
|
||||
templinfo["WhatAbout"] = about
|
||||
err := readviews.Execute(w, "account.html", templinfo)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -1923,14 +1988,19 @@ func somedays() string {
|
|||
}
|
||||
|
||||
func avatate(w http.ResponseWriter, r *http.Request) {
|
||||
if debugMode {
|
||||
loadAvatarColors()
|
||||
}
|
||||
n := r.FormValue("a")
|
||||
a := avatar(n)
|
||||
a := genAvatar(n)
|
||||
w.Header().Set("Cache-Control", "max-age="+somedays())
|
||||
w.Write(a)
|
||||
}
|
||||
|
||||
func serveasset(w http.ResponseWriter, r *http.Request) {
|
||||
if !debugMode {
|
||||
w.Header().Set("Cache-Control", "max-age=7776000")
|
||||
}
|
||||
dir := viewDir
|
||||
if r.URL.Path == "/local.css" {
|
||||
dir = dataDir
|
||||
|
@ -1939,7 +2009,9 @@ func serveasset(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
func servehelp(w http.ResponseWriter, r *http.Request) {
|
||||
name := mux.Vars(r)["name"]
|
||||
if !debugMode {
|
||||
w.Header().Set("Cache-Control", "max-age=3600")
|
||||
}
|
||||
http.ServeFile(w, r, viewDir+"/docs/"+name)
|
||||
}
|
||||
func servehtml(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -1951,7 +2023,7 @@ func servehtml(w http.ResponseWriter, r *http.Request) {
|
|||
if r.URL.Path == "/about" {
|
||||
templinfo["Sensors"] = getSensors()
|
||||
}
|
||||
if u == nil {
|
||||
if u == nil && !debugMode {
|
||||
w.Header().Set("Cache-Control", "max-age=60")
|
||||
}
|
||||
err := readviews.Execute(w, r.URL.Path[1:]+".html", templinfo)
|
||||
|
@ -1960,14 +2032,16 @@ func servehtml(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
func serveemu(w http.ResponseWriter, r *http.Request) {
|
||||
xid := mux.Vars(r)["xid"]
|
||||
emu := mux.Vars(r)["emu"]
|
||||
|
||||
w.Header().Set("Cache-Control", "max-age="+somedays())
|
||||
http.ServeFile(w, r, dataDir+"/emus/"+xid)
|
||||
http.ServeFile(w, r, dataDir+"/emus/"+emu)
|
||||
}
|
||||
func servememe(w http.ResponseWriter, r *http.Request) {
|
||||
xid := mux.Vars(r)["xid"]
|
||||
meme := mux.Vars(r)["meme"]
|
||||
|
||||
w.Header().Set("Cache-Control", "max-age="+somedays())
|
||||
http.ServeFile(w, r, dataDir+"/memes/"+xid)
|
||||
http.ServeFile(w, r, dataDir+"/memes/"+meme)
|
||||
}
|
||||
|
||||
func servefile(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -2073,6 +2147,7 @@ func honkhonkline() {
|
|||
func apihandler(w http.ResponseWriter, r *http.Request) {
|
||||
u := login.GetUserInfo(r)
|
||||
userid := u.UserID
|
||||
user, _ := butwhatabout(u.Username)
|
||||
action := r.FormValue("action")
|
||||
wait, _ := strconv.ParseInt(r.FormValue("wait"), 10, 0)
|
||||
log.Printf("api request '%s' on behalf of %s", action, u.Username)
|
||||
|
@ -2110,6 +2185,13 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
|
|||
j := junk.New()
|
||||
j["honks"] = honks
|
||||
j.Write(w)
|
||||
case "sendactivity":
|
||||
public := r.FormValue("public") == "1"
|
||||
rcpts := boxuprcpts(user, r.Form["rcpt"], public)
|
||||
msg := []byte(r.FormValue("msg"))
|
||||
for rcpt := range rcpts {
|
||||
go deliverate(0, userid, rcpt, msg)
|
||||
}
|
||||
default:
|
||||
http.Error(w, "unknown action", http.StatusNotFound)
|
||||
return
|
||||
|
@ -2158,9 +2240,8 @@ func serve() {
|
|||
go redeliverator()
|
||||
go tracker()
|
||||
|
||||
debug := false
|
||||
getconfig("debug", &debug)
|
||||
readviews = templates.Load(debug,
|
||||
getconfig("debug", &debugMode)
|
||||
readviews = templates.Load(debugMode,
|
||||
viewDir+"/views/honkpage.html",
|
||||
viewDir+"/views/honkfrags.html",
|
||||
viewDir+"/views/honkers.html",
|
||||
|
@ -2178,11 +2259,12 @@ func serve() {
|
|||
viewDir+"/views/onts.html",
|
||||
viewDir+"/views/honkpage.js",
|
||||
)
|
||||
if !debug {
|
||||
if !debugMode {
|
||||
assets := []string{viewDir + "/views/style.css", dataDir + "/views/local.css", viewDir + "/views/honkpage.js"}
|
||||
for _, s := range assets {
|
||||
savedassetparams[s] = getassetparam(s)
|
||||
}
|
||||
loadAvatarColors()
|
||||
}
|
||||
|
||||
for _, h := range preservehooks {
|
||||
|
@ -2214,8 +2296,8 @@ func serve() {
|
|||
getters.HandleFunc("/o", thelistingoftheontologies)
|
||||
getters.HandleFunc("/o/{name:.+}", showontology)
|
||||
getters.HandleFunc("/d/{xid:[[:alnum:].]+}", servefile)
|
||||
getters.HandleFunc("/emu/{xid:[[:alnum:]_.-]+}", serveemu)
|
||||
getters.HandleFunc("/meme/{xid:[[:alnum:]_.-]+}", servememe)
|
||||
getters.HandleFunc("/emu/{emu:[^.]*[^/]+}", serveemu)
|
||||
getters.HandleFunc("/meme/{meme:[^.]*[^/]+}", servememe)
|
||||
getters.HandleFunc("/.well-known/webfinger", fingerlicker)
|
||||
|
||||
getters.HandleFunc("/server", serveractor)
|
||||
|
|
Loading…
Reference in New Issue