diff --git a/activity.go b/activity.go index 5f2095e..5361abd 100644 --- a/activity.go +++ b/activity.go @@ -1208,30 +1208,30 @@ func honkworldwide(user *WhatAbout, honk *Honk) { } } -var oldjonkers = cache.New(cache.Options{Filler: func(name string) ([]byte, bool) { - user, err := butwhatabout(name) - if err != nil { - return nil, false - } +func junkuser(user *WhatAbout) []byte { about := markitzero(user.About) j := junk.New() j["@context"] = itiswhatitis j["id"] = user.URL - j["type"] = "Person" j["inbox"] = user.URL + "/inbox" j["outbox"] = user.URL + "/outbox" - j["followers"] = user.URL + "/followers" - j["following"] = user.URL + "/following" j["name"] = user.Display j["preferredUsername"] = user.Name j["summary"] = about - j["url"] = user.URL - a := junk.New() - a["type"] = "Image" - a["mediaType"] = "image/png" - a["url"] = fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL)) - j["icon"] = a + if user.ID > 0 { + j["type"] = "Person" + j["url"] = user.URL + j["followers"] = user.URL + "/followers" + j["following"] = user.URL + "/following" + a := junk.New() + a["type"] = "Image" + a["mediaType"] = "image/png" + a["url"] = fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL)) + j["icon"] = a + } else { + j["type"] = "Service" + } k := junk.New() k["id"] = user.URL + "#key" k["owner"] = user.URL @@ -1240,7 +1240,15 @@ var oldjonkers = cache.New(cache.Options{Filler: func(name string) ([]byte, bool var buf bytes.Buffer j.Write(&buf) - return buf.Bytes(), true + return buf.Bytes() +} + +var oldjonkers = cache.New(cache.Options{Filler: func(name string) ([]byte, bool) { + user, err := butwhatabout(name) + if err != nil { + return nil, false + } + return junkuser(user), true }, Duration: 1 * time.Minute}) func asjonker(name string) ([]byte, bool) { diff --git a/database.go b/database.go index a88d744..6086e87 100644 --- a/database.go +++ b/database.go @@ -27,6 +27,7 @@ import ( "time" "humungus.tedunangst.com/r/webs/cache" + "humungus.tedunangst.com/r/webs/httpsig" "humungus.tedunangst.com/r/webs/login" ) @@ -43,6 +44,27 @@ var someusers = cache.New(cache.Options{Filler: func(name string) (*WhatAbout, b return user, true }}) +var oldserveruser *WhatAbout + +func getserveruser() *WhatAbout { + if oldserveruser == nil { + db := opendatabase() + row := db.QueryRow("select userid, username, displayname, about, pubkey, seckey from users where userid = ?", serverUID) + user := new(WhatAbout) + var seckey string + err := row.Scan(&user.ID, &user.Name, &user.Display, &user.About, &user.Key, &seckey) + if err == nil { + user.SecKey, _, err = httpsig.DecodeKey(seckey) + } + if err != nil { + log.Panicf("trouble getting server user: %s", err) + } + user.URL = fmt.Sprintf("https://%s/server", serverName) + oldserveruser = user + } + return oldserveruser +} + func butwhatabout(name string) (*WhatAbout, error) { var user *WhatAbout ok := someusers.Get(name, &user) @@ -98,7 +120,7 @@ func getdubs(userid int64) []*Honker { func allusers() []login.UserInfo { var users []login.UserInfo - rows, _ := opendatabase().Query("select userid, username from users") + rows, _ := opendatabase().Query("select userid, username from users where userid > 0") defer rows.Close() for rows.Next() { var u login.UserInfo @@ -695,7 +717,7 @@ func prepareStatements(db *sql.DB) { stmtGetFileData = preparetodie(blobdb, "select media, content from filedata where xid = ?") stmtFindXonk = preparetodie(db, "select honkid from honks where userid = ? and xid = ?") stmtFindFile = preparetodie(db, "select fileid, xid from filemeta where url = ? and local = 1") - stmtWhatAbout = preparetodie(db, "select userid, username, displayname, about, pubkey, options from users where username = ?") + stmtWhatAbout = preparetodie(db, "select userid, username, displayname, about, pubkey, options from users where username = ? and userid > 0") stmtSaveDub = preparetodie(db, "insert into honkers (userid, name, xid, flavor) values (?, ?, ?, ?)") stmtAddDoover = preparetodie(db, "insert into doovers (dt, tries, username, rcpt, msg) values (?, ?, ?, ?, ?)") stmtGetDoovers = preparetodie(db, "select dooverid, dt from doovers") diff --git a/honk.go b/honk.go index 96f949e..4f1c0bb 100644 --- a/honk.go +++ b/honk.go @@ -16,6 +16,7 @@ package main import ( + "crypto/rsa" "fmt" "html/template" "log" @@ -33,8 +34,11 @@ type WhatAbout struct { Key string URL string SkinnyCSS bool + SecKey *rsa.PrivateKey } +const serverUID int64 = -2 + type Honk struct { ID int64 UserID int64 diff --git a/upgradedb.go b/upgradedb.go index cf4404f..98c281c 100644 --- a/upgradedb.go +++ b/upgradedb.go @@ -24,7 +24,7 @@ import ( "time" ) -var myVersion = 27 +var myVersion = 28 func doordie(db *sql.DB, s string, args ...interface{}) { _, err := db.Exec(s, args...) @@ -303,6 +303,10 @@ func upgradedb() { doordie(db, "update config set value = 27 where key = 'dbversion'") fallthrough case 27: + createserveruser(db) + doordie(db, "update config set value = 28 where key = 'dbversion'") + fallthrough + case 28: default: log.Fatalf("can't upgrade unknown version %d", dbversion) diff --git a/util.go b/util.go index 3b304a2..db12bb1 100644 --- a/util.go +++ b/util.go @@ -118,6 +118,11 @@ func initdb() { log.Print(err) return } + err = createserveruser(db) + if err != nil { + log.Print(err) + return + } fmt.Printf("listen address: ") addr, err := r.ReadString('\n') @@ -297,7 +302,31 @@ func createuser(db *sql.DB, r *bufio.Reader) error { if err != nil { return err } - _, err = db.Exec("insert into users (username, displayname, about, hash, pubkey, seckey, options) values (?, ?, ?, ?, ?, ?, ?)", name, name, "what about me?", hash, pubkey, seckey, "") + about := "what about me?" + _, err = db.Exec("insert into users (username, displayname, about, hash, pubkey, seckey, options) values (?, ?, ?, ?, ?, ?, ?)", name, name, about, hash, pubkey, seckey, "") + if err != nil { + return err + } + return nil +} + +func createserveruser(db *sql.DB) error { + k, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return err + } + pubkey, err := httpsig.EncodeKey(&k.PublicKey) + if err != nil { + return err + } + seckey, err := httpsig.EncodeKey(k) + if err != nil { + return err + } + name := "server" + about := "server" + hash := "*" + _, err = db.Exec("insert into users (userid, username, displayname, about, hash, pubkey, seckey, options) values (?, ?, ?, ?, ?, ?, ?, ?)", serverUID, name, name, about, hash, pubkey, seckey, "") if err != nil { return err } diff --git a/web.go b/web.go index e421967..e3ee9e7 100644 --- a/web.go +++ b/web.go @@ -410,6 +410,51 @@ func inbox(w http.ResponseWriter, r *http.Request) { } } +func serverinbox(w http.ResponseWriter, r *http.Request) { + if stealthmode(serverUID, r) { + http.NotFound(w, r) + return + } + var buf bytes.Buffer + io.Copy(&buf, r.Body) + payload := buf.Bytes() + j, err := junk.Read(bytes.NewReader(payload)) + if err != nil { + log.Printf("bad payload: %s", err) + io.WriteString(os.Stdout, "bad payload\n") + os.Stdout.Write(payload) + io.WriteString(os.Stdout, "\n") + return + } + if crappola(j) { + return + } + 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 != "" { + log.Printf("bad signature from %s", keyname) + io.WriteString(os.Stdout, "bad payload\n") + os.Stdout.Write(payload) + io.WriteString(os.Stdout, "\n") + } + http.Error(w, "what did you call me?", http.StatusTeapot) + return + } + what, _ := j.GetString("type") + log.Printf("server got a %s", what) +} + +func serveractor(w http.ResponseWriter, r *http.Request) { + if stealthmode(serverUID, r) { + http.NotFound(w, r) + return + } + user := getserveruser() + j := junkuser(user) + w.Write(j) +} + func ximport(w http.ResponseWriter, r *http.Request) { u := login.GetUserInfo(r) xid := strings.TrimSpace(r.FormValue("xid")) @@ -1735,6 +1780,7 @@ func serve() { savedassetparams[s] = getassetparam(s) } } + getserveruser() mux := mux.NewRouter() mux.Use(login.Checker) @@ -1763,6 +1809,9 @@ func serve() { getters.HandleFunc("/meme/{xid:[[:alnum:]_.-]+}", servememe) getters.HandleFunc("/.well-known/webfinger", fingerlicker) + getters.HandleFunc("/server", serveractor) + posters.HandleFunc("/server/inbox", serverinbox) + getters.HandleFunc("/style.css", servecss) getters.HandleFunc("/local.css", servecss) getters.HandleFunc("/honkpage.js", serveasset)