---
doc/ext/set-account-password.md | 31 ++++++++++++++++++++++++downstream.go | 42 +++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)
create mode 100644 doc/ext/set-account-password.md
diff --git a/doc/ext/set-account-password.md b/doc/ext/set-account-password.md
new file mode 100644
index 000000000000..22df4c662525
--- /dev/null+++ b/doc/ext/set-account-password.md
@@ -0,0 +1,31 @@
+## Description++This document describes the `soju.im/set-account-password` extension. It+provides a command for clients to change their account password.++## Capability++This specification adds the `soju.im/set-account-password` capability which+indicates that the server accepts the `SETPASSWORD` command.++## Command++ SETPASSWORD <new-password>++The `SETPASSWORD` command requests to change the current user's account+password.++## Response++ SETPASSWORD SUCCESS++Sent by the server when the `SETPASSWORD` command succeeds.++ FAIL SETPASSWORD WEAK_PASSWORD <message>++Sent by the server if the password is considered too weak.++ FAIL SETPASSWORD UNACCEPTABLE_PASSWORD <message>++Sent by the server if the password is invalid for any reason other than+weakness.
diff --git a/downstream.go b/downstream.go
index 08199137cc7f..122ef0fe3b1f 100644
--- a/downstream.go+++ b/downstream.go
@@ -256,6 +256,12 @@ var needAllDownstreamCaps = map[string]string{
"draft/extended-monitor": "",
}
+// bouncerDownstreamCaps is the list of downstream capabilities that are only+// supported when the downstream connection isn't bound to an upstream network.+var bouncerDownstreamCaps = map[string]string{+ "soju.im/set-account-password": "",+}+// passthroughIsupport is the set of ISUPPORT tokens that are directly passed
// through from the upstream server to downstream clients.
//
@@ -1123,6 +1129,14 @@ func (dc *downstreamConn) updateSupportedCaps() {
}
}
+ for k, v := range bouncerDownstreamCaps {+ if dc.network == nil {+ dc.setSupportedCap(k, v)+ } else {+ dc.unsetSupportedCap(k)+ }+ }+ if uc := dc.upstream(); uc != nil && uc.supportsSASL("PLAIN") {
dc.setSupportedCap("sasl", "PLAIN")
} else if dc.network != nil {
@@ -3065,6 +3079,34 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
dc.SendMessage(dc.marshalMessage(msg, uc.network))
}
})
+ case "SETPASSWORD":+ var newPassword string+ if err := parseMessageParams(msg, &newPassword); err != nil {+ return err+ }++ // copy the user record because we'll mutate it+ record := dc.user.User+ if err := record.SetPassword(newPassword); err != nil {+ dc.logger.Printf("failed setting account password: %v", err)+ return ircError{&irc.Message{+ Command: "FAIL",+ Params: []string{"SETPASSWORD", "INTERNAL_ERROR", "Internal error"},+ }}+ }++ if err := dc.user.updateUser(ctx, &record); err != nil {+ dc.logger.Printf("failed updating user: %v", err)+ return ircError{&irc.Message{+ Command: "FAIL",+ Params: []string{"SETPASSWORD", "INTERNAL_ERROR", "Internal error"},+ }}+ }++ dc.SendMessage(&irc.Message{+ Command: "SETPASSWORD",+ Params: []string{"SUCCESS"},+ }) case "BOUNCER":
var subcommand string
if err := parseMessageParams(msg, &subcommand); err != nil {
base-commit: fe40c51ff0ee78f1bfe7c35a86d654bf64678067
--
2.36.1