mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
fix(join): stop rotating a returning member's webmail password (#104)
handleJoin called setWebmailPassword unconditionally, so every visit to join@ minted a fresh Roundcube password -- including for members who registered and verified long ago. join@ is the address people remember, so returning members type it out of habit. Doing so silently invalidated their webmail login: the replacement password scrolled past once in the join output, the old one was already dead, and nothing in the session said a credential had changed. The failure surfaces later, as "my password stopped working", with no way to connect it back to having typed join@ -- and it reads like a compromised account, which is an alarming thing to hand someone over a no-op visit. Mint the password only while actually onboarding: a new key registering, or an account that completes email verification in this session. A returning member is told the password is unchanged and pointed at passwd@, which already sets one password across git, mail and chat and is key-gated, so it doubles as the forgot-password path. Also replace the bare webmail URL line shown when no password is minted with the full url/login block, so the address and where to get credentials are always visible, and distinguish "unchanged" (returning) from "not set yet" (onboarding, but Mailu was unreachable). Verified by inspection only: this box has no Go toolchain (repo needs 1.26), so the build is left to CI. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
20cdb6432d
commit
41174eec03
1 changed files with 46 additions and 6 deletions
|
|
@ -753,6 +753,10 @@ func (a *app) handleJoin(s ssh.Session) {
|
||||||
wish.Fatalln(s, "registration error: "+err.Error())
|
wish.Fatalln(s, "registration error: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Whether this session actually onboarded anyone: a brand-new key here, or an
|
||||||
|
// account that finishes email verification below. Everything with a credential
|
||||||
|
// side effect keys off this rather than off reaching join@ at all.
|
||||||
|
onboarding := !found
|
||||||
if !found {
|
if !found {
|
||||||
// New key: show the acceptable-use terms and require acceptance before
|
// New key: show the acceptable-use terms and require acceptance before
|
||||||
// creating the account, then let the visitor pick their own handle (a
|
// creating the account, then let the visitor pick their own handle (a
|
||||||
|
|
@ -783,6 +787,7 @@ func (a *app) handleJoin(s ssh.Session) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.notifySignup(u)
|
a.notifySignup(u)
|
||||||
|
onboarding = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every verified member gets a homepage at https://<host>/~<name> and a
|
// Every verified member gets a homepage at https://<host>/~<name> and a
|
||||||
|
|
@ -791,11 +796,26 @@ func (a *app) handleJoin(s ssh.Session) {
|
||||||
_ = a.ensureMailbox(u)
|
_ = a.ensureMailbox(u)
|
||||||
// Give them a webmail password so free members can log into webmail. The
|
// Give them a webmail password so free members can log into webmail. The
|
||||||
// in-BBS reader uses the gateway master user and needs no password, but
|
// in-BBS reader uses the gateway master user and needs no password, but
|
||||||
// Roundcube does. (Re)set on each join@; they can change it in webmail.
|
// Roundcube does.
|
||||||
webmailPW := a.setWebmailPassword(u)
|
//
|
||||||
|
// Only while ONBOARDING. This used to run on every join@, which quietly broke
|
||||||
|
// returning members: join@ is the address people remember, so typing it again
|
||||||
|
// out of habit rotated a live Roundcube password: the replacement scrolled past
|
||||||
|
// in this output once, the old one was already dead, and nothing said a
|
||||||
|
// credential had changed. Rotating a working password must never be a side
|
||||||
|
// effect of saying hello -- passwd@ is the deliberate way to change one, and it
|
||||||
|
// is already key-gated, so it doubles as the forgot-password path.
|
||||||
|
var webmailPW string
|
||||||
|
if onboarding {
|
||||||
|
webmailPW = a.setWebmailPassword(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
lead := " You're in. One login gets you everything — no other servers to ssh into:"
|
||||||
|
if !onboarding {
|
||||||
|
lead = " You're already a member — nothing changed. One login gets you everything:"
|
||||||
|
}
|
||||||
includes := []string{
|
includes := []string{
|
||||||
" You're in. One login gets you everything — no other servers to ssh into:",
|
lead,
|
||||||
"",
|
"",
|
||||||
" ssh " + u.Name + "@" + a.host,
|
" ssh " + u.Name + "@" + a.host,
|
||||||
"",
|
"",
|
||||||
|
|
@ -806,7 +826,8 @@ func (a *app) handleJoin(s ssh.Session) {
|
||||||
" • the arcade & games",
|
" • the arcade & games",
|
||||||
" • your homepage https://" + a.host + "/~" + u.Name,
|
" • your homepage https://" + a.host + "/~" + u.Name,
|
||||||
}
|
}
|
||||||
if a.webmailURL != "" && webmailPW != "" {
|
switch {
|
||||||
|
case a.webmailURL != "" && webmailPW != "":
|
||||||
includes = append(includes,
|
includes = append(includes,
|
||||||
"",
|
"",
|
||||||
" Webmail (read your mail in a browser):",
|
" Webmail (read your mail in a browser):",
|
||||||
|
|
@ -814,8 +835,27 @@ func (a *app) handleJoin(s ssh.Session) {
|
||||||
" • login "+a.mailAddress(u.Name),
|
" • login "+a.mailAddress(u.Name),
|
||||||
" • password "+webmailPW+" (change it in webmail Settings)",
|
" • password "+webmailPW+" (change it in webmail Settings)",
|
||||||
)
|
)
|
||||||
} else if a.webmailURL != "" {
|
case a.webmailURL != "" && !onboarding:
|
||||||
includes = append(includes, " • webmail "+a.webmailURL)
|
// Say the password is untouched. A returning member who came here looking
|
||||||
|
// for their credentials needs to know this visit did not change them, and
|
||||||
|
// where to go if they have lost them.
|
||||||
|
includes = append(includes,
|
||||||
|
"",
|
||||||
|
" Webmail (read your mail in a browser):",
|
||||||
|
" • url "+a.webmailURL,
|
||||||
|
" • login "+a.mailAddress(u.Name),
|
||||||
|
" • password unchanged — forgot it? ssh passwd@"+a.host,
|
||||||
|
)
|
||||||
|
case a.webmailURL != "":
|
||||||
|
// Onboarding, but minting the password failed (Mailu down or unconfigured).
|
||||||
|
// Don't imply one is waiting for them -- point at the way to set one.
|
||||||
|
includes = append(includes,
|
||||||
|
"",
|
||||||
|
" Webmail (read your mail in a browser):",
|
||||||
|
" • url "+a.webmailURL,
|
||||||
|
" • login "+a.mailAddress(u.Name),
|
||||||
|
" • password not set yet — set one: ssh passwd@"+a.host,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
wish.Println(s, "\n"+strings.Join(includes, "\n"))
|
wish.Println(s, "\n"+strings.Join(includes, "\n"))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue