From 15983e2f962e6923c8d3d897da84f44d834988d3 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 12 Oct 2026 13:25:58 +0200 Subject: [PATCH] betterbird: an account's own aliases and identities that do not send by SMTP share no outgoing server, and the pins name their vendors on purpose (review 36, review 35 of mesh-controller #251) The shared-server check refused an adopted account for its own alias, and counted Owl's, local folders' and feeds' identities as users of the default server, though they never send by SMTP. The controller now judges an upstream pin's host like any name, so each pin declares its vendor. --- .../cmd/betterbird-tools/accounts_test.go | 33 +++++++++++++++++++ .../cmd/betterbird-tools/adoption.go | 21 ++++++++++-- modules/betterbird/module.json | 10 ++++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/modules/betterbird/cmd/betterbird-tools/accounts_test.go b/modules/betterbird/cmd/betterbird-tools/accounts_test.go index 5642af6a..87796008 100644 --- a/modules/betterbird/cmd/betterbird-tools/accounts_test.go +++ b/modules/betterbird/cmd/betterbird-tools/accounts_test.go @@ -483,3 +483,36 @@ func TestACredentialRefusalNamesNoAccount(t *testing.T) { t.Fatalf("%v", err) } } + +func TestAnAccountsOwnAliasesAndNonMailIdentitiesDoNotShareItsOutgoingServer(t *testing.T) { + f := newFake(t) + f.profileWithAccounts() + f.noPackage() + links(t, nil) + f.declare("// none") + os.RemoveAll(filepath.Join(f.Root, "proc", "4000")) + // account1 has an alias identity on smtp1; smtp1 is the default server; Owl's account and local folders + // have identities that name no outgoing server. + prefs := strings.Replace(f.read(profileDir+"/prefs.js"), `"mail.account.account1.identities", "id1"`, `"mail.account.account1.identities", "id1,id1b"`, 1) + prefs = strings.Replace(prefs, `"mail.account.account2.server", "server2");`, `"mail.account.account2.server", "server2");`+"\n"+ + `user_pref("mail.account.account2.identities", "id2");`, 1) + + `user_pref("mail.identity.id1b.useremail", "alias@mail.example.org");` + "\n" + + `user_pref("mail.identity.id1b.smtpServer", "smtp1");` + "\n" + + `user_pref("mail.identity.id2.useremail", "local@mail.example.org");` + "\n" + + `user_pref("mail.smtp.defaultserver", "smtp1");` + "\n" + f.write(profileDir+"/prefs.js", prefs) + f.declareAccounts(adoptable) + if err := f.Prepare(); err != nil { + t.Fatalf("an account's own alias, and identities that do not send by SMTP, are no sharing: %v", err) + } + // An identity of another mail account naming no server does use the default one. + f.write(profileDir+"/prefs.js", strings.Replace(prefs, `"account1,account3,account2"`, `"account1,account3,account2,account6"`, 1)+ + `user_pref("mail.account.account6.server", "server6");`+"\n"+ + `user_pref("mail.account.account6.identities", "id6");`+"\n"+ + `user_pref("mail.identity.id6.useremail", "six@mail.example.org");`+"\n"+ + `user_pref("mail.server.server6.type", "pop3");`+"\n") + os.Remove(filepath.Join(f.Root, testHome, recordFile)) + if err := f.Prepare(); err == nil || !strings.Contains(err.Error(), "also used by identity id6") { + t.Fatalf("%v", err) + } +} diff --git a/modules/betterbird/cmd/betterbird-tools/adoption.go b/modules/betterbird/cmd/betterbird-tools/adoption.go index ecf137e6..8a65066e 100644 --- a/modules/betterbird/cmd/betterbird-tools/adoption.go +++ b/modules/betterbird/cmd/betterbird-tools/adoption.go @@ -148,10 +148,23 @@ func resolveAccounts(accounts map[string]Account, prefs map[string]string, rec m // ADR 0317 §2 adopts the outgoing server the identity names and leaves the lists as they are, so the module // does not give the identity a server of its own; it refuses, with the remedy. func refuseSharedOutgoing(resolved []resolvedAccount, prefs map[string]string, have []profileAccount) []resolvedAccount { + // Every identity of an adopted or created account is its own, its aliases too (review 36). + accountOf := map[string]profileAccount{} + kindOf := map[string]string{} + for _, a := range have { + accountOf[a.Key] = a + for _, id := range a.Identities { + kindOf[id] = a.Kind + } + } ours := map[string]bool{} for _, r := range resolved { - if r.How != refused { - ours[r.Keys.Identity] = true + if r.How == refused { + continue + } + ours[r.Keys.Identity] = true + for _, id := range accountOf[r.Keys.Account].Identities { + ours[id] = true } } defaultServer := unquote(prefs["mail.smtp.defaultserver"]) @@ -163,7 +176,9 @@ func refuseSharedOutgoing(resolved []resolvedAccount, prefs map[string]string, h } seen[id] = true server := unquote(prefs["mail.identity."+id+".smtpServer"]) - if server == "" { + // Only a mail account's identity sends through the default server when it names none: Owl's, local + // folders and feeds do not send by SMTP (review 36). + if server == "" && (kindOf[id] == "imap" || kindOf[id] == "pop3") { server = defaultServer } if server != "" { diff --git a/modules/betterbird/module.json b/modules/betterbird/module.json index 59dc8e5a..049fc8e4 100644 --- a/modules/betterbird/module.json +++ b/modules/betterbird/module.json @@ -125,7 +125,10 @@ "url": "https://www.betterbird.eu/downloads/LinuxArchive/betterbird-153.4.0esr-bb10.en-US.linux-x86_64.tar.xz", "sha256": "38dd24890a66b4cf9a45bc24e15192e00c26b929e1bb8df7974c16a4539129e2", "version": "153.4.0esr-bb10", - "within": "betterbird" + "within": "betterbird", + "names-on-purpose": { + "www.betterbird.eu": "Betterbird's project publishes its Linux release there; the build seat fetches it once, by its pinned sha256 (novox/hq ADR 0316 §2)" + } }, { "name": "owl", @@ -133,7 +136,10 @@ "url": "https://www.beonex.com/owl/owl.xpi", "sha256": "a54cc3d52113b34f97942ee19190947dee23561e2217f18db3d80ac023991221", "version": "1.5.6.1", - "file": "owl.xpi" + "file": "owl.xpi", + "names-on-purpose": { + "www.beonex.com": "Owl's vendor publishes its xpi there; the build seat fetches it once, by its pinned sha256 (novox/hq ADR 0316 §6)" + } }, { "name": "distribution",