aboutsummaryrefslogtreecommitdiff
path: root/cap_sasl.go
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2024-12-08 15:17:50 +0800
committerRunxi Yu <me@runxiyu.org>2024-12-08 15:17:50 +0800
commit9e1c9c5f43e2f0cf2dd1fa29b1ba3512dbbaeb7e (patch)
treec176990b7e54b292b70dcfe1f3bed5fa1ab630a3 /cap_sasl.go
parentcommandHandlers -> CommandHandlers (diff)
downloadmeseircd-9e1c9c5f43e2f0cf2dd1fa29b1ba3512dbbaeb7e.tar.gz
meseircd-9e1c9c5f43e2f0cf2dd1fa29b1ba3512dbbaeb7e.tar.zst
meseircd-9e1c9c5f43e2f0cf2dd1fa29b1ba3512dbbaeb7e.zip
Implement SASL stub
Diffstat (limited to 'cap_sasl.go')
-rw-r--r--cap_sasl.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/cap_sasl.go b/cap_sasl.go
new file mode 100644
index 0000000..7044efb
--- /dev/null
+++ b/cap_sasl.go
@@ -0,0 +1,86 @@
+package main
+
+import (
+ "encoding/base64"
+ "bytes"
+)
+
+type ExtraSasl struct {
+ AuthMethod string
+}
+
+const (
+ RPL_LOGGEDIN = "900"
+ RPL_LOGGEDOUT = "901"
+ ERR_NICKLOCKED = "902"
+ RPL_SASLSUCCESS = "903"
+ ERR_SASLFAIL = "904"
+ ERR_SASLTOOLONG = "905"
+ ERR_SASLABORTED = "906"
+ ERR_SASLALREADY = "907"
+ RPL_SASLMECHS = "908"
+)
+
+const (
+ panicSaslMethod = "stored illegal SASL method"
+)
+
+func init() {
+ Caps["sasl"] = "PLAIN,EXTERNAL"
+ CommandHandlers["AUTHENTICATE"] = handleClientAuthenticate
+}
+
+func handleClientAuthenticate(msg RMsg, client *Client) error {
+ _, ok := client.Caps["sasl"]
+ if !ok {
+ return client.Send(MakeMsg(self, "TODO", "you're trying to sasl without requesting for it"))
+ }
+
+ if len(msg.Params) < 1 {
+ return client.Send(MakeMsg(self, ERR_NEEDMOREPARAMS, "AUTHENTICATE", "Not enough parameters"))
+ }
+
+ extraSasl_, ok := client.Extra["sasl"]
+ if !ok {
+ client.Extra["sasl"] = &ExtraSasl{}
+ extraSasl_ = client.Extra["sasl"]
+ }
+ extraSasl, ok := extraSasl_.(*ExtraSasl)
+ if !ok {
+ panic(panicType)
+ }
+
+ switch extraSasl.AuthMethod {
+ case "":
+ if msg.Params[0] != "PLAIN" && msg.Params[0] != "EXTERNAL" {
+ return client.Send(MakeMsg(self, ERR_SASLFAIL, client.Nick, "SASL authentication failed (invalid method)"))
+ }
+ extraSasl.AuthMethod = msg.Params[0]
+ return client.Send(MakeMsg(self, "AUTHENTICATE", "+"))
+ case "*": // Abort
+ extraSasl.AuthMethod = ""
+ return client.Send(MakeMsg(self, ERR_SASLFAIL, client.Nick, "SASL authentication failed (aborted)"))
+ case "EXTERNAL":
+ extraSasl.AuthMethod = ""
+ return client.Send(MakeMsg(self, ERR_SASLFAIL, client.Nick, "SASL authentication failed"))
+ case "PLAIN":
+ extraSasl.AuthMethod = ""
+ saslPlainData, err := base64.StdEncoding.DecodeString(msg.Params[0])
+ if err != nil {
+ return client.Send(MakeMsg(self, ERR_SASLFAIL, client.Nick, "SASL authentication failed (base64 decoding error)"))
+ }
+ saslPlainSegments := bytes.Split(saslPlainData, []byte{0})
+ if len(saslPlainSegments) != 3 {
+ return client.Send(MakeMsg(self, ERR_SASLFAIL, client.Nick, "SASL authentication failed (not three segments)"))
+ }
+ _ = string(saslPlainSegments[0]) // authzid unused
+ authcid := string(saslPlainSegments[1])
+ passwd := string(saslPlainSegments[2])
+ if authcid == "runxiyu" && passwd == "hunter2" {
+ return client.Send(MakeMsg(self, RPL_SASLSUCCESS, client.Nick, "SASL authentication successful"))
+ }
+ return client.Send(MakeMsg(self, ERR_SASLFAIL, client.Nick, "SASL authentication failed"))
+ default:
+ panic(panicSaslMethod)
+ }
+}