diff --git a/activity.go b/activity.go index 17c03c6..ccbe5fd 100644 --- a/activity.go +++ b/activity.go @@ -912,7 +912,7 @@ func rubadubdub(user *WhatAbout, req junk.Junk) { j["published"] = time.Now().UTC().Format(time.RFC3339) j["object"] = req - deliverate(0, user.Name, actor, j.ToBytes()) + deliverate(0, user.ID, actor, j.ToBytes()) } func itakeitallback(user *WhatAbout, xid string) { @@ -931,7 +931,7 @@ func itakeitallback(user *WhatAbout, xid string) { j["object"] = f j["published"] = time.Now().UTC().Format(time.RFC3339) - deliverate(0, user.Name, xid, j.ToBytes()) + deliverate(0, user.ID, xid, j.ToBytes()) } func subsub(user *WhatAbout, xid string) { @@ -952,7 +952,7 @@ func subsub(user *WhatAbout, xid string) { j.Write(&buf) msg := buf.Bytes() - deliverate(0, user.Name, xid, msg) + deliverate(0, user.ID, xid, msg) } // returns activity, object @@ -1191,7 +1191,7 @@ func honkworldwide(user *WhatAbout, honk *Honk) { } } for a := range rcpts { - go deliverate(0, user.Name, a, msg) + go deliverate(0, user.ID, a, msg) } } diff --git a/database.go b/database.go index 6086e87..c9006b8 100644 --- a/database.go +++ b/database.go @@ -31,43 +31,55 @@ import ( "humungus.tedunangst.com/r/webs/login" ) -var someusers = cache.New(cache.Options{Filler: func(name string) (*WhatAbout, bool) { - row := stmtWhatAbout.QueryRow(name) +func userfromrow(row *sql.Row) (*WhatAbout, error) { user := new(WhatAbout) - var options string - err := row.Scan(&user.ID, &user.Name, &user.Display, &user.About, &user.Key, &options) + var seckey, options string + err := row.Scan(&user.ID, &user.Name, &user.Display, &user.About, &user.Key, &seckey, &options) + if err == nil { + user.SecKey, _, err = httpsig.DecodeKey(seckey) + } + if err != nil { + return nil, err + } + if user.ID > 0 { + user.URL = fmt.Sprintf("https://%s/%s/%s", serverName, userSep, user.Name) + user.SkinnyCSS = strings.Contains(options, " skinny ") + } else { + user.URL = fmt.Sprintf("https://%s/%s", serverName, user.Name) + } + return user, nil +} + +var somenamedusers = cache.New(cache.Options{Filler: func(name string) (*WhatAbout, bool) { + row := stmtUserByName.QueryRow(name) + user, err := userfromrow(row) if err != nil { return nil, false } - user.URL = fmt.Sprintf("https://%s/%s/%s", serverName, userSep, user.Name) - user.SkinnyCSS = strings.Contains(options, " skinny ") return user, true }}) -var oldserveruser *WhatAbout +var somenumberedusers = cache.New(cache.Options{Filler: func(userid int64) (*WhatAbout, bool) { + row := stmtUserByNumber.QueryRow(userid) + user, err := userfromrow(row) + if err != nil { + return nil, false + } + return user, true +}}) 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 + var user *WhatAbout + ok := somenumberedusers.Get(serverUID, &user) + if !ok { + log.Panicf("lost server user") } - return oldserveruser + return user } func butwhatabout(name string) (*WhatAbout, error) { var user *WhatAbout - ok := someusers.Get(name, &user) + ok := somenamedusers.Get(name, &user) if !ok { return nil, fmt.Errorf("no user: %s", name) } @@ -655,7 +667,7 @@ func cleanupdb(arg string) { var stmtHonkers, stmtDubbers, stmtSaveHonker, stmtUpdateFlavor, stmtUpdateHonker *sql.Stmt var stmtAnyXonk, stmtOneXonk, stmtPublicHonks, stmtUserHonks, stmtHonksByCombo, stmtHonksByConvoy *sql.Stmt var stmtHonksByOntology, stmtHonksForUser, stmtHonksForMe, stmtSaveDub, stmtHonksByXonker *sql.Stmt -var stmtHonksBySearch, stmtHonksByHonker, stmtSaveHonk, stmtWhatAbout *sql.Stmt +var stmtHonksBySearch, stmtHonksByHonker, stmtSaveHonk, stmtUserByName, stmtUserByNumber *sql.Stmt var stmtEventHonks, stmtOneBonk, stmtFindZonk, stmtFindXonk, stmtSaveDonk *sql.Stmt var stmtFindFile, stmtGetFileData, stmtSaveFileData, stmtSaveFile *sql.Stmt var stmtAddDoover, stmtGetDoovers, stmtLoadDoover, stmtZapDoover, stmtOneHonker *sql.Stmt @@ -717,11 +729,12 @@ 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 = ? and userid > 0") + stmtUserByName = preparetodie(db, "select userid, username, displayname, about, pubkey, seckey, options from users where username = ? and userid > 0") + stmtUserByNumber = preparetodie(db, "select userid, username, displayname, about, pubkey, seckey, options from users where userid = ?") stmtSaveDub = preparetodie(db, "insert into honkers (userid, name, xid, flavor) values (?, ?, ?, ?)") - stmtAddDoover = preparetodie(db, "insert into doovers (dt, tries, username, rcpt, msg) values (?, ?, ?, ?, ?)") + stmtAddDoover = preparetodie(db, "insert into doovers (dt, tries, userid, rcpt, msg) values (?, ?, ?, ?, ?)") stmtGetDoovers = preparetodie(db, "select dooverid, dt from doovers") - stmtLoadDoover = preparetodie(db, "select tries, username, rcpt, msg from doovers where dooverid = ?") + stmtLoadDoover = preparetodie(db, "select tries, userid, rcpt, msg from doovers where dooverid = ?") stmtZapDoover = preparetodie(db, "delete from doovers where dooverid = ?") stmtThumbBiters = preparetodie(db, "select userid, name, wherefore from zonkers") stmtFindZonk = preparetodie(db, "select zonkerid from zonkers where userid = ? and name = ? and wherefore = 'zonk'") diff --git a/deliverator.go b/deliverator.go index afe87bc..d9efb7e 100644 --- a/deliverator.go +++ b/deliverator.go @@ -31,7 +31,7 @@ type Doover struct { When time.Time } -func sayitagain(goarounds int, username string, rcpt string, msg []byte) { +func sayitagain(goarounds int64, userid int64, rcpt string, msg []byte) { var drift time.Duration switch goarounds { case 1: @@ -50,7 +50,7 @@ func sayitagain(goarounds int, username string, rcpt string, msg []byte) { } drift += time.Duration(notrand.Int63n(int64(drift / 10))) when := time.Now().UTC().Add(drift) - _, err := stmtAddDoover.Exec(when.Format(dbtimeformat), goarounds, username, rcpt, msg) + _, err := stmtAddDoover.Exec(when.Format(dbtimeformat), goarounds, userid, rcpt, msg) if err != nil { log.Printf("error saving doover: %s", err) } @@ -81,11 +81,16 @@ func truckcomesin() { garagelock.Unlock() } -func deliverate(goarounds int, username string, rcpt string, msg []byte) { +func deliverate(goarounds int64, userid int64, rcpt string, msg []byte) { truckgoesout() defer truckcomesin() - keyname, key := ziggy(username) + var ki *KeyInfo + ok := ziggies.Get(userid, &ki) + if !ok { + log.Printf("lost key for delivery") + return + } var inbox string // already did the box indirection if rcpt[0] == '%' { @@ -95,15 +100,15 @@ func deliverate(goarounds int, username string, rcpt string, msg []byte) { ok := boxofboxes.Get(rcpt, &box) if !ok { log.Printf("failed getting inbox for %s", rcpt) - sayitagain(goarounds+1, username, rcpt, msg) + sayitagain(goarounds+1, userid, rcpt, msg) return } inbox = box.In } - err := PostMsg(keyname, key, inbox, msg) + err := PostMsg(ki.keyname, ki.seckey, inbox, msg) if err != nil { log.Printf("failed to post json to %s: %s", inbox, err) - sayitagain(goarounds+1, username, rcpt, msg) + sayitagain(goarounds+1, userid, rcpt, msg) return } } @@ -151,11 +156,11 @@ func redeliverator() { nexttime := now.Add(24 * time.Hour) for _, d := range doovers { if d.When.Before(now) { - var goarounds int - var username, rcpt string + var goarounds, userid int64 + var rcpt string var msg []byte row := stmtLoadDoover.QueryRow(d.ID) - err := row.Scan(&goarounds, &username, &rcpt, &msg) + err := row.Scan(&goarounds, &userid, &rcpt, &msg) if err != nil { log.Printf("error scanning doover: %s", err) continue @@ -166,7 +171,7 @@ func redeliverator() { continue } log.Printf("redeliverating %s try %d", rcpt, goarounds) - deliverate(goarounds, username, rcpt, msg) + deliverate(goarounds, userid, rcpt, msg) } else if d.When.Before(nexttime) { nexttime = d.When } diff --git a/fun.go b/fun.go index cb0f1b4..d956cfc 100644 --- a/fun.go +++ b/fun.go @@ -581,37 +581,31 @@ func oneofakind(a []string) []string { return a[:j] } -var ziggies = make(map[string]*rsa.PrivateKey) -var zaggies = make(map[string]*rsa.PublicKey) -var ziggylock sync.Mutex - -func ziggy(username string) (keyname string, key *rsa.PrivateKey) { - ziggylock.Lock() - key = ziggies[username] - ziggylock.Unlock() - if key == nil { - db := opendatabase() - row := db.QueryRow("select seckey from users where username = ?", username) - var data string - row.Scan(&data) - var err error - key, _, err = httpsig.DecodeKey(data) - if err != nil { - log.Printf("error decoding %s seckey: %s", username, err) - return - } - ziggylock.Lock() - ziggies[username] = key - ziggylock.Unlock() +var ziggies = cache.New(cache.Options{Filler: func(userid int64) (*KeyInfo, bool) { + var user *WhatAbout + ok := somenumberedusers.Get(userid, &user) + if !ok { + return nil, false } - keyname = fmt.Sprintf("https://%s/%s/%s#key", serverName, userSep, username) - return + ki := new(KeyInfo) + ki.keyname = user.URL + "#key" + ki.seckey = user.SecKey + return ki, true +}}) + +func ziggy(userid int64) *KeyInfo { + var ki *KeyInfo + ziggies.Get(userid, &ki) + return ki } +var zaggies = make(map[string]*rsa.PublicKey) +var zaggylock sync.Mutex + func zaggy(keyname string) (key *rsa.PublicKey) { - ziggylock.Lock() + zaggylock.Lock() key = zaggies[keyname] - ziggylock.Unlock() + zaggylock.Unlock() if key != nil { return } @@ -655,9 +649,9 @@ func zaggy(keyname string) (key *rsa.PublicKey) { return } } - ziggylock.Lock() + zaggylock.Lock() zaggies[keyname] = key - ziggylock.Unlock() + zaggylock.Unlock() return } @@ -666,9 +660,9 @@ func makeitworksomehowwithoutregardforkeycontinuity(keyname string, r *http.Requ if err != nil { log.Printf("error deleting key: %s", err) } - ziggylock.Lock() + zaggylock.Lock() delete(zaggies, keyname) - ziggylock.Unlock() + zaggylock.Unlock() return httpsig.VerifyRequest(r, payload, zaggy) } diff --git a/honk.go b/honk.go index 4f1c0bb..19ba382 100644 --- a/honk.go +++ b/honk.go @@ -37,6 +37,11 @@ type WhatAbout struct { SecKey *rsa.PrivateKey } +type KeyInfo struct { + keyname string + seckey *rsa.PrivateKey +} + const serverUID int64 = -2 type Honk struct { diff --git a/schema.sql b/schema.sql index 7732d9f..c84f71b 100644 --- a/schema.sql +++ b/schema.sql @@ -5,7 +5,7 @@ create table filemeta (fileid integer primary key, xid text, name text, descript create table honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, combos text); create table xonkers (xonkerid integer primary key, name text, info text, flavor 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, username text, rcpt text, msg blob); +create table doovers(dooverid integer primary key, dt text, tries integer, userid integer, rcpt text, msg blob); create table onts (ontology text, honkid integer); create table honkmeta (honkid integer, genus text, json text); create table hfcs (hfcsid integer primary key, userid integer, json text); diff --git a/upgradedb.go b/upgradedb.go index 98c281c..7336b7d 100644 --- a/upgradedb.go +++ b/upgradedb.go @@ -24,7 +24,7 @@ import ( "time" ) -var myVersion = 28 +var myVersion = 29 func doordie(db *sql.DB, s string, args ...interface{}) { _, err := db.Exec(s, args...) @@ -307,6 +307,11 @@ func upgradedb() { doordie(db, "update config set value = 28 where key = 'dbversion'") fallthrough case 28: + doordie(db, "drop table doovers") + doordie(db, "create table doovers(dooverid integer primary key, dt text, tries integer, userid integer, rcpt text, msg blob)") + doordie(db, "update config set value = 29 where key = 'dbversion'") + fallthrough + case 29: default: log.Fatalf("can't upgrade unknown version %d", dbversion) diff --git a/web.go b/web.go index 51e5c4f..9256623 100644 --- a/web.go +++ b/web.go @@ -245,8 +245,11 @@ func ping(user *WhatAbout, who string) { j["id"] = user.URL + "/ping/" + xfiltrate() j["actor"] = user.URL j["to"] = who - keyname, key := ziggy(user.Name) - err := PostJunk(keyname, key, box.In, j) + ki := ziggy(user.ID) + if ki == nil { + return + } + err := PostJunk(ki.keyname, ki.seckey, box.In, j) if err != nil { log.Printf("can't send ping: %s", err) return @@ -268,8 +271,11 @@ func pong(user *WhatAbout, who string, obj string) { j["actor"] = user.URL j["to"] = who j["object"] = obj - keyname, key := ziggy(user.Name) - err := PostJunk(keyname, key, box.In, j) + ki := ziggy(user.ID) + if ki == nil { + return + } + err := PostJunk(ki.keyname, ki.seckey, box.In, j) if err != nil { log.Printf("can't send pong: %s", err) return @@ -860,7 +866,8 @@ func saveuser(w http.ResponseWriter, r *http.Request) { if err != nil { log.Printf("error bouting what: %s", err) } - someusers.Clear(u.Username) + somenamedusers.Clear(u.Username) + somenumberedusers.Clear(u.UserID) http.Redirect(w, r, "/account", http.StatusSeeOther) } @@ -1805,7 +1812,6 @@ func serve() { savedassetparams[s] = getassetparam(s) } } - getserveruser() mux := mux.NewRouter() mux.Use(login.Checker)