diff --git a/.hgignore b/.hgignore index b5de9ba..a00a9cf 100644 --- a/.hgignore +++ b/.hgignore @@ -1,4 +1,9 @@ -.*\.db +syntax: glob +.preflightcheck +*.db +*.db-shm +*.db-wal memes emus honk +violations.json diff --git a/.hgtags b/.hgtags index 8f08ce3..963d5f9 100644 --- a/.hgtags +++ b/.hgtags @@ -38,3 +38,4 @@ bc1bcfb9c0cc86b3c63325b07e13a36b9d4500f0 v0.9.7 916cefdc24363b6e7e193dbde82632c17f58adfd v0.9.8 4b8cf31560b7d1e1696af109b158766c4ce823ab v0.9.9 d7c3a01e7aaef67c40920bbc4e8507350fc33e31 v0.9.91 +b1e7ac92a58a7183310b1a5cca8222d65f242d81 v1.0.0 diff --git a/README b/README index 8e32b20..12da7d2 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ honk --- features +## features Take control of your honks and join the federation. An ActivityPub server with minimal setup and support costs. @@ -17,7 +17,7 @@ The button to submit a new honk says "it's gonna be honked". The honk mission is to work well if it's what you want. This does not imply the goal is to be what you want. --- build +## build It should be sufficient to type make after unpacking a release. You'll need a go compiler version 1.16 or later. And libsqlite3. @@ -26,7 +26,7 @@ Even on a fast machine, building from source can take several seconds. Development sources: hg clone https://humungus.tedunangst.com/r/honk --- setup +## setup honk expects to be fronted by a TLS terminating reverse proxy. @@ -40,17 +40,17 @@ servername: (public DNS name: honk.example.com) Then run honk. ./honk --- upgrade +## upgrade old-honk backup `date +backup-%F` ./honk upgrade ./honk --- documentation +## documentation There is a more complete incomplete manual. This is just the README. --- guidelines +## guidelines One honk per day, or call it an "eighth-tenth" honk. If your honk frequency changes, so will the number of honks. @@ -67,6 +67,6 @@ 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 +## disclaimer Do not use honk to contact emergency services. diff --git a/activity.go b/activity.go index 4cf0285..c91b32c 100644 --- a/activity.go +++ b/activity.go @@ -133,6 +133,9 @@ var flightdeck = gate.NewSerializer() var signGets = true func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, error) { + if rejectorigin(userid, url, false) { + return nil, fmt.Errorf("rejected origin: %s", url) + } client := http.DefaultClient sign := func(req *http.Request) error { var ki *KeyInfo @@ -147,7 +150,7 @@ func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, sign = nil } fn := func() (interface{}, error) { - at := thefakename + at := theonetruename if strings.Contains(url, ".well-known/webfinger?resource") { at = "application/jrd+json" } @@ -490,7 +493,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { maxdepth := 10 currenttid := "" goingup := 0 - var xonkxonkfn func(junk.Junk, string, bool, bool) *Honk + var xonkxonkfn func(junk.Junk, string, bool, string) *Honk qutify := func(user *WhatAbout, content string) string { if depth >= maxdepth { @@ -522,7 +525,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { } prevdepth := depth depth = maxdepth - xonkxonkfn(j, originate(m), false, false) + xonkxonkfn(j, originate(m), false, "") depth = prevdepth } } @@ -541,10 +544,10 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { ilog.Printf("error getting onemore: %s: %s", xid, err) return } - xonkxonkfn(obj, originate(xid), false, false) + xonkxonkfn(obj, originate(xid), false, "") } - xonkxonkfn = func(item junk.Junk, origin string, isUpdate bool, isAnnounce bool) *Honk { + xonkxonkfn = func(item junk.Junk, origin string, isUpdate bool, bonker string) *Honk { id, _ := item.GetString("id") what := firstofmany(item, "type") dt, ok := item.GetString("published") @@ -624,6 +627,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { if !isUpdate && !needbonkid(user, xid) { return nil } + bonker, _ = item.GetString("actor") origin = originate(xid) if ok && originate(id) == origin { dlog.Printf("using object in announce for %s", xid) @@ -632,9 +636,10 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { obj, err = GetJunkHardMode(user.ID, xid) if err != nil { ilog.Printf("error getting bonk: %s: %s", xid, err) + return nil } } - return xonkxonkfn(obj, origin, isUpdate, true) + return xonkxonkfn(obj, origin, isUpdate, bonker) case "Update": isUpdate = true fallthrough @@ -656,7 +661,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { ilog.Printf("no object for creation %s", id) return nil } - return xonkxonkfn(obj, origin, isUpdate, isAnnounce) + return xonkxonkfn(obj, origin, isUpdate, bonker) case "Read": xid, ok = item.GetString("object") if ok { @@ -669,7 +674,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { ilog.Printf("error getting read: %s", err) return nil } - return xonkxonkfn(obj, originate(xid), false, false) + return xonkxonkfn(obj, originate(xid), false, "") } return nil case "Add": @@ -685,7 +690,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { ilog.Printf("error getting add: %s", err) return nil } - return xonkxonkfn(obj, originate(xid), false, false) + return xonkxonkfn(obj, originate(xid), false, "") } return nil case "Move": @@ -714,7 +719,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { obj = item what = "event" case "ChatMessage": - isAnnounce = false + bonker = "" obj = item what = "chonk" default: @@ -722,7 +727,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { dumpactivity(item) return nil } - if isAnnounce { + if bonker != "" { what = "bonk" } @@ -755,7 +760,9 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { if xonk.Honker == "" { xonk.Honker = extractattrto(obj) } - xonk.Oonker = extractattrto(obj) + if bonker != "" { + xonk.Honker, xonk.Oonker = bonker, xonk.Honker + } if xonk.Oonker == xonk.Honker { xonk.Oonker = "" } @@ -1125,7 +1132,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { return &xonk } - return xonkxonkfn(item, origin, false, false) + return xonkxonkfn(item, origin, false, "") } func dumpactivity(item junk.Junk) { diff --git a/bloat.go b/bloat.go index e89675f..245add8 100644 --- a/bloat.go +++ b/bloat.go @@ -14,3 +14,38 @@ // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. package main + +import ( + "io" + "net" + "time" +) + +func qotd() { + var qotdaddr string + getconfig("qotdaddr", &qotdaddr) + if qotdaddr == "" { + return + } + s, err := net.Listen("tcp", ":8017") + if err != nil { + return + } + for { + c, err := s.Accept() + if err != nil { + time.Sleep(time.Second) + continue + } + honks := getpublichonks() + for _, honk := range honks { + if !firstclass(honk) { + continue + } + io.WriteString(c, honk.Noise) + io.WriteString(c, "\n") + break + } + c.Close() + } +} diff --git a/database.go b/database.go index e398a22..8c9696b 100644 --- a/database.go +++ b/database.go @@ -1121,7 +1121,7 @@ func cleanupdb(arg string) { if err != nil { elog.Fatal(err) } - for xid, _ := range filexids { + for xid := range filexids { _, err = tx.Exec("delete from filedata where xid = ?", xid) if err != nil { elog.Fatal(err) diff --git a/docs/changelog.txt b/docs/changelog.txt index 5e9a09e..5e7adbd 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,15 +1,19 @@ changelog -=== next +### 1.0.0 Happy Honker + ++ A great big honk composition text box. + More reliable search. + Secret tags. -+ Mention links locally. ++ Mentions link locally. + ::: spoiler markdown ++ Fix the bonk and zonk crash. + + New threaded display order. + Improved search. @@ -18,15 +22,19 @@ changelog + Import from instagram. -+ improve handling of some Page and Link objects ++ Improve handling of some Page and Link objects. -+ search can now load external posts ++ Other federation fixes. -=== 0.9.91 One More Time ++ Search can now load external posts. + ++ Some hypercard opengraph markup for previews. + +### 0.9.91 One More Time + Swallow a follow bug. -=== 0.9.9 Eat the Bugs +### 0.9.9 Eat the Bugs + Some fixes for image descriptions. @@ -58,7 +66,7 @@ changelog + Try to fix hoot again because Twitter did a Twitter. -=== 0.9.8 Tentative Tentacle +### 0.9.8 Tentative Tentacle + Switch database to WAL mode. @@ -88,7 +96,7 @@ changelog + Some improved html and markdown. -=== 0.9.7 Witless Weekender +### 0.9.7 Witless Weekender +++ Word guessing game. Wonk wonk! @@ -104,7 +112,7 @@ changelog + Printing is prettier than ever before. -=== 0.9.6 Virile Vigorous and Potent +### 0.9.6 Virile Vigorous and Potent + A bug, a fix, a bug fix, a fix bug. @@ -120,17 +128,17 @@ changelog + Fix hoot to work with Twitter's latest crap. -=== 0.9.5 Emergency Ejection +### 0.9.5 Emergency Ejection + Fix honk init user creation. -=== 0.9.4 Collegiate Colloquialism +### 0.9.4 Collegiate Colloquialism + Add validation to some more user inputs to prevent mistakes. + Easier to use ping command. -=== 0.9.3 Notacanthous Nutshell +### 0.9.3 Notacanthous Nutshell ++ backup command. @@ -152,11 +160,11 @@ changelog - Custom lingo for those who don't like honking. -=== 0.9.2 Malleable Maltote +### 0.9.2 Malleable Maltote + Fix compilation on mac. -=== 0.9.1 Late Stage Lusciousness +### 0.9.1 Late Stage Lusciousness ++ Boing boom tschak chonky chatter. Chat messages with Pleroma. @@ -176,7 +184,7 @@ changelog + A few API refinements and additions. -=== 0.9.0 Monitor vs Merrimack +### 0.9.0 Monitor vs Merrimack --- Add Reactions. @@ -194,7 +202,7 @@ changelog + Maybe possible to use @user@example.com wihtout subdomain. -=== 0.8.6 Sartorial Headpiece +### 0.8.6 Sartorial Headpiece ++ Import command now supports the elephant in the room. @@ -220,7 +228,7 @@ changelog + More flexible meme names. -=== 0.8.5 Turnkey Blaster +### 0.8.5 Turnkey Blaster + Codenames in changelog. @@ -240,17 +248,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 Game Warden +### 0.8.2 Game Warden ++ Import command to preserve those embarssassing old posts from Twitter. @@ -266,7 +274,7 @@ changelog + "Bug" fixes. -=== 0.8.1 +### 0.8.1 ++ Make it easier to upgrade by decoupling data dir from ".". @@ -278,7 +286,7 @@ changelog Syntax highlighting for code blocks. Something resembling an actual manual. -=== 0.8.0 Ordinary Octology +### 0.8.0 Ordinary Octology +++ Add Honk Filtering and Censorship System (HFCS). @@ -333,7 +341,7 @@ changelog - Sometimes the cached state of the @me feed becomes unsynced. Acked status may display incorrectly. -=== 0.7.7 More 7 Than Ever +### 0.7.7 More 7 Than Ever + Add another retry to workaround pixelfed's general unreliability. @@ -345,11 +353,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. @@ -361,7 +369,7 @@ changelog + What may be considered UI improvements. -=== 0.7.4 +### 0.7.4 + Ever more bug fixes. @@ -377,19 +385,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 Father Mother Maiden Crone Honker Bonker Zonker +### 0.7.0 Father Mother Maiden Crone Honker Bonker Zonker +++ Auto fetching and inlining of hoots. @@ -419,12 +427,12 @@ changelog + Add max-width for video tag. -=== 0.6.0 Sixy Delights +### 0.6.0 Sixy Delights Most records from this time of primitive development have been lost. -=== 0.5.0 Halfway to Heaven +### 0.5.0 Halfway to Heaven -=== 0.4.0 Fore Score +### 0.4.0 Fore Score -=== 0.3.0 Valorous Varaha +### 0.3.0 Valorous Varaha diff --git a/docs/honk.8 b/docs/honk.8 index 63178ec..966a939 100644 --- a/docs/honk.8 +++ b/docs/honk.8 @@ -266,10 +266,10 @@ honk-v98> ./honk -datadir ../honkdata admin honk-v98> date; ./honk -log honk.log -datadir ../honkdata .Ed .Pp -The views directory includes a sample pleroma.css to change color scheme. +The views directory includes a sample mastodon.css to change color scheme. .Bd -literal -offset indent honk-v98> mkdir ../honkdata/views -honk-v98> cp views/pleroma.css ../honkdata/views/local.css +honk-v98> cp views/mastodon.css ../honkdata/views/local.css .Ed .Pp Upgrade to the next version. diff --git a/go.mod b/go.mod index 15379a8..a19ad41 100644 --- a/go.mod +++ b/go.mod @@ -9,5 +9,5 @@ require ( golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 humungus.tedunangst.com/r/go-sqlite3 v1.1.3 - humungus.tedunangst.com/r/webs v0.6.67 + humungus.tedunangst.com/r/webs v0.6.68 ) diff --git a/go.sum b/go.sum index 0f8e915..5fef797 100644 --- a/go.sum +++ b/go.sum @@ -25,5 +25,5 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI= humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M= -humungus.tedunangst.com/r/webs v0.6.67 h1:OO5UkQa+bHeiIrZ5IGR9JGtgGPsKsYlRJEVk1bSt+Qo= -humungus.tedunangst.com/r/webs v0.6.67/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc= +humungus.tedunangst.com/r/webs v0.6.68 h1:veKjASf1krPf4o3O7hMRsNvE4+Z6LzXVso/qMccZntk= +humungus.tedunangst.com/r/webs v0.6.68/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc= diff --git a/honk.go b/honk.go index 8466c67..edb9d22 100644 --- a/honk.go +++ b/honk.go @@ -16,27 +16,14 @@ package main import ( - "flag" - "fmt" "html/template" - golog "log" - "log/syslog" - notrand "math/rand" - "os" "strconv" "strings" "time" "humungus.tedunangst.com/r/webs/httpsig" - "humungus.tedunangst.com/r/webs/log" ) -var softwareVersion = "develop" - -func init() { - notrand.Seed(time.Now().Unix()) -} - type WhatAbout struct { ID int64 Name string @@ -277,218 +264,3 @@ const ( SomeActor SomeCollection ) - -var serverName string -var serverPrefix string -var masqName string -var dataDir = "." -var viewDir = "." -var iconName = "icon.png" -var serverMsg template.HTML -var aboutMsg template.HTML -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 reexecArgs(cmd string) []string { - args := []string{"-datadir", dataDir} - args = append(args, log.Args()...) - args = append(args, cmd) - return args -} - -var elog, ilog, dlog *golog.Logger - -func main() { - flag.StringVar(&dataDir, "datadir", dataDir, "data directory") - flag.StringVar(&viewDir, "viewdir", viewDir, "view directory") - flag.Parse() - - log.Init(log.Options{Progname: "honk", Facility: syslog.LOG_UUCP}) - elog = log.E - ilog = log.I - dlog = log.D - - args := flag.Args() - cmd := "run" - if len(args) > 0 { - cmd = args[0] - } - switch cmd { - case "init": - initdb() - case "upgrade": - upgradedb() - case "version": - fmt.Println(softwareVersion) - os.Exit(0) - } - db := opendatabase() - dbversion := 0 - getconfig("dbversion", &dbversion) - if dbversion != myVersion { - elog.Fatal("incorrect database version. run upgrade.") - } - getconfig("servermsg", &serverMsg) - getconfig("aboutmsg", &aboutMsg) - getconfig("loginmsg", &loginMsg) - getconfig("servername", &serverName) - getconfig("masqname", &masqName) - if masqName == "" { - masqName = serverName - } - serverPrefix = fmt.Sprintf("https://%s/", serverName) - getconfig("usersep", &userSep) - getconfig("honksep", &honkSep) - getconfig("devel", &develMode) - getconfig("fasttimeout", &fastTimeout) - getconfig("slowtimeout", &slowTimeout) - getconfig("signgets", &signGets) - prepareStatements(db) - switch cmd { - case "admin": - adminscreen() - case "import": - if len(args) != 4 { - elog.Fatal("import username mastodon|twitter srcdir") - } - importMain(args[1], args[2], args[3]) - case "devel": - if len(args) != 2 { - elog.Fatal("need an argument: devel (on|off)") - } - switch args[1] { - case "on": - setconfig("devel", 1) - case "off": - setconfig("devel", 0) - default: - elog.Fatal("argument must be on or off") - } - case "setconfig": - if len(args) != 3 { - elog.Fatal("need an argument: setconfig key val") - } - var val interface{} - var err error - if val, err = strconv.Atoi(args[2]); err != nil { - val = args[2] - } - setconfig(args[1], val) - case "adduser": - adduser() - case "deluser": - if len(args) < 2 { - fmt.Printf("usage: honk deluser username\n") - return - } - deluser(args[1]) - case "chpass": - if len(args) < 2 { - fmt.Printf("usage: honk chpass username\n") - 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 "sendmsg": - if len(args) < 4 { - fmt.Printf("usage: honk send username filename rcpt\n") - return - } - user, err := butwhatabout(args[1]) - if err != nil { - fmt.Printf("user not found\n") - return - } - data, err := os.ReadFile(args[2]) - if err != nil { - fmt.Printf("can't read file\n") - return - } - deliverate(user.ID, args[3], data) - case "cleanup": - arg := "30" - if len(args) > 1 { - 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 "backup": - if len(args) < 2 { - fmt.Printf("usage: honk backup dirname\n") - return - } - name := args[1] - svalbard(name) - case "ping": - if len(args) < 3 { - fmt.Printf("usage: honk ping (from username) (to username or url)\n") - return - } - name := args[1] - targ := args[2] - user, err := butwhatabout(name) - if err != nil { - elog.Printf("unknown user") - return - } - ping(user, targ) - case "run": - serve() - case "backend": - backendServer() - case "test": - ElaborateUnitTests() - default: - elog.Fatal("unknown command") - } -} diff --git a/import.go b/import.go index 8ac5c34..7dfbe6e 100644 --- a/import.go +++ b/import.go @@ -338,7 +338,7 @@ func importTwitter(username, source string) { } var tweets []*Tweet - fd, err := os.Open(source + "/tweet.js") + fd, err := os.Open(source + "/tweets.js") if err != nil { elog.Fatal(err) } @@ -375,11 +375,6 @@ func importTwitter(username, source string) { continue } - if t.Tweet.FavoriteCount == "0" || t.Tweet.FavoriteCount == "" { - log.Printf("skipping, unworthy tweet") - continue - } - what := "honk" noise := "" if parent := tweetmap[t.Tweet.InReplyToStatusID]; parent != nil { diff --git a/main.go b/main.go new file mode 100644 index 0000000..5e944d1 --- /dev/null +++ b/main.go @@ -0,0 +1,255 @@ +// +// Copyright (c) 2019 Ted Unangst +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +package main + +import ( + "flag" + "fmt" + "html/template" + golog "log" + "log/syslog" + notrand "math/rand" + "os" + "strconv" + "time" + + "humungus.tedunangst.com/r/webs/log" +) + +var softwareVersion = "develop" + +func init() { + notrand.Seed(time.Now().Unix()) +} + +var serverName string +var serverPrefix string +var masqName string +var dataDir = "." +var viewDir = "." +var iconName = "icon.png" +var serverMsg template.HTML +var aboutMsg template.HTML +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 reexecArgs(cmd string) []string { + args := []string{"-datadir", dataDir} + args = append(args, log.Args()...) + args = append(args, cmd) + return args +} + +var elog, ilog, dlog *golog.Logger + +func main() { + flag.StringVar(&dataDir, "datadir", dataDir, "data directory") + flag.StringVar(&viewDir, "viewdir", viewDir, "view directory") + flag.Parse() + + log.Init(log.Options{Progname: "honk", Facility: syslog.LOG_UUCP}) + elog = log.E + ilog = log.I + dlog = log.D + + if os.Geteuid() == 0 { + elog.Fatalf("do not run honk as root") + } + + args := flag.Args() + cmd := "run" + if len(args) > 0 { + cmd = args[0] + } + switch cmd { + case "init": + initdb() + case "upgrade": + upgradedb() + case "version": + fmt.Println(softwareVersion) + os.Exit(0) + } + db := opendatabase() + dbversion := 0 + getconfig("dbversion", &dbversion) + if dbversion != myVersion { + elog.Fatal("incorrect database version. run upgrade.") + } + getconfig("servermsg", &serverMsg) + getconfig("aboutmsg", &aboutMsg) + getconfig("loginmsg", &loginMsg) + getconfig("servername", &serverName) + getconfig("masqname", &masqName) + if masqName == "" { + masqName = serverName + } + serverPrefix = fmt.Sprintf("https://%s/", serverName) + getconfig("usersep", &userSep) + getconfig("honksep", &honkSep) + getconfig("devel", &develMode) + getconfig("fasttimeout", &fastTimeout) + getconfig("slowtimeout", &slowTimeout) + getconfig("signgets", &signGets) + prepareStatements(db) + switch cmd { + case "admin": + adminscreen() + case "import": + if len(args) != 4 { + elog.Fatal("import username mastodon|twitter srcdir") + } + importMain(args[1], args[2], args[3]) + case "devel": + if len(args) != 2 { + elog.Fatal("need an argument: devel (on|off)") + } + switch args[1] { + case "on": + setconfig("devel", 1) + case "off": + setconfig("devel", 0) + default: + elog.Fatal("argument must be on or off") + } + case "setconfig": + if len(args) != 3 { + elog.Fatal("need an argument: setconfig key val") + } + var val interface{} + var err error + if val, err = strconv.Atoi(args[2]); err != nil { + val = args[2] + } + setconfig(args[1], val) + case "adduser": + adduser() + case "deluser": + if len(args) < 2 { + fmt.Printf("usage: honk deluser username\n") + return + } + deluser(args[1]) + case "chpass": + if len(args) < 2 { + fmt.Printf("usage: honk chpass username\n") + 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 "sendmsg": + if len(args) < 4 { + fmt.Printf("usage: honk send username filename rcpt\n") + return + } + user, err := butwhatabout(args[1]) + if err != nil { + fmt.Printf("user not found\n") + return + } + data, err := os.ReadFile(args[2]) + if err != nil { + fmt.Printf("can't read file\n") + return + } + deliverate(user.ID, args[3], data) + case "cleanup": + arg := "30" + if len(args) > 1 { + 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 "backup": + if len(args) < 2 { + fmt.Printf("usage: honk backup dirname\n") + return + } + name := args[1] + svalbard(name) + case "ping": + if len(args) < 3 { + fmt.Printf("usage: honk ping (from username) (to username or url)\n") + return + } + name := args[1] + targ := args[2] + user, err := butwhatabout(name) + if err != nil { + elog.Printf("unknown user") + return + } + ping(user, targ) + case "run": + serve() + case "backend": + backendServer() + case "test": + ElaborateUnitTests() + default: + elog.Fatal("unknown command") + } +} diff --git a/memes/twowires.jpg b/memes/twowires.jpg new file mode 100644 index 0000000..5d663a9 Binary files /dev/null and b/memes/twowires.jpg differ diff --git a/sensors.go b/sensors.go index 4428c07..ef9b15f 100644 --- a/sensors.go +++ b/sensors.go @@ -16,10 +16,38 @@ package main import ( + "runtime/debug" "syscall" "time" ) +func init() { + if softwareVersion != "develop" { + return + } + bi, ok := debug.ReadBuildInfo() + if !ok { + return + } + var vcs, rev, mod string + for _, bs := range bi.Settings { + if bs.Key == "vcs" { + vcs = "/" + bs.Value + } + if bs.Key == "vcs.revision" { + rev = bs.Value + if len(rev) > 12 { + rev = rev[:12] + } + rev = "-" + rev + } + if bs.Key == "vcs.modified" && bs.Value == "true" { + mod = "+" + } + } + softwareVersion += vcs + rev + mod +} + type Sensors struct { Memory float64 Uptime float64 diff --git a/views/mastodon.css b/views/mastodon.css new file mode 100644 index 0000000..4f30453 --- /dev/null +++ b/views/mastodon.css @@ -0,0 +1,7 @@ +html { + --bg-page: #353a49; + --bg-dark: #393f4f; + --fg: #fff; + --hl: #6364ff; + --fg-subtle: #606984 +} diff --git a/views/pleroma.css b/views/pleroma.css deleted file mode 100644 index b25439a..0000000 --- a/views/pleroma.css +++ /dev/null @@ -1,7 +0,0 @@ -html { - --bg-page: #1b2735; - --bg-dark: #121a24; - --fg: #b9b9ba; - --hl: #d8a070; - --fg-subtle: rgba(185, 185, 186, 0.5); -} diff --git a/views/style.css b/views/style.css index 326edb5..cb2dae2 100644 --- a/views/style.css +++ b/views/style.css @@ -146,7 +146,7 @@ textarea { font-size: 1em; background: var(--bg-page); color: var(--fg); - width: 600px; + width: 100%; height: 4em; margin-bottom: 0.5em; box-sizing: border-box; diff --git a/web.go b/web.go index c7507cc..905327c 100644 --- a/web.go +++ b/web.go @@ -602,7 +602,7 @@ func xzone(w http.ResponseWriter, r *http.Request) { honkers = append(honkers, Honker{XID: xid}) } rows.Close() - for i, _ := range honkers { + for i := range honkers { _, honkers[i].Handle = handles(honkers[i].XID) } templinfo := getInfo(r) @@ -733,6 +733,7 @@ func showuser(w http.ResponseWriter, r *http.Request) { templinfo["Name"] = user.Name templinfo["WhatAbout"] = user.HTAbout templinfo["ServerMessage"] = "" + templinfo["APAltLink"] = templates.Sprintf("", user.URL) if u != nil { templinfo["HonkCSRF"] = login.GetCSRF("honkhonk", r) } @@ -2560,6 +2561,9 @@ func apihandler(w http.ResponseWriter, r *http.Request) { } func fiveoh(w http.ResponseWriter, r *http.Request) { + if !develMode { + return + } fd, err := os.OpenFile("violations.json", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { elog.Printf("error opening violations! %s", err) @@ -2606,7 +2610,11 @@ func bgmonitor() { func addcspheaders(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Security-Policy", "default-src 'none'; script-src 'self'; connect-src 'self'; style-src 'self'; img-src 'self'; media-src 'self'; report-uri /csp-violation") + policy := "default-src 'none'; script-src 'self'; connect-src 'self'; style-src 'self'; img-src 'self'; media-src 'self'" + if develMode { + policy += "; report-uri /csp-violation" + } + w.Header().Set("Content-Security-Policy", policy) next.ServeHTTP(w, r) }) } @@ -2648,6 +2656,7 @@ func serve() { go redeliverator() go tracker() go bgmonitor() + go qotd() loadLingo() emuinit()