~emersion/public-inbox

chathistorysync: Use BOUNCER BIND to bind to bouncer networks v1 PROPOSED

Adnan Maolood: 1
 Use BOUNCER BIND to bind to bouncer networks

 2 files changed, 62 insertions(+), 11 deletions(-)
#737946 .build.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/public-inbox/patches/31190/mbox | git am -3
Learn more about email & git

[PATCH chathistorysync] Use BOUNCER BIND to bind to bouncer networks Export this patch

Also update the client to use SASL authentication.
---
 client.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 main.go   |  9 +++++---
 2 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/client.go b/client.go
index 492a75b..c1030ca 100644
--- a/client.go
+++ b/client.go
@@ -1,7 +1,10 @@
package main

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"errors"
	"fmt"
	"log"
	"net"
@@ -67,20 +70,14 @@ func dialTLS(addr string) (*client, error) {
	}, nil
}

func (c *client) Register(nick, pass string) {
	caps := []string{"draft/chathistory", "message-tags", "batch", "echo-message", "server-time", "causal.agency/passive", "soju.im/bouncer-networks"}
func (c *client) Authenticate(nick, pass, netid string) error {
	caps := []string{"draft/chathistory", "sasl", "message-tags", "batch", "echo-message", "server-time", "causal.agency/passive", "soju.im/bouncer-networks"}
	for _, name := range caps {
		c.WriteMessage(&irc.Message{
			Command: "CAP",
			Params:  []string{"REQ", name},
		})
	}
	if pass != "" {
		c.WriteMessage(&irc.Message{
			Command: "PASS",
			Params:  []string{pass},
		})
	}
	c.WriteMessage(&irc.Message{
		Command: "NICK",
		Params:  []string{nick},
@@ -89,10 +86,53 @@ func (c *client) Register(nick, pass string) {
		Command: "USER",
		Params:  []string{nick, "0", "*", nick},
	})

	// Wait for SASL authentication to complete
loop:
	for {
		msg, err := c.ReadMessage()
		if err != nil {
			return err
		}

		switch msg.Command {
		case "AUTHENTICATE":
			challenge := msg.Params[0]
			if challenge != "+" {
				return fmt.Errorf("unexpected SASL challenge %q", challenge)
			}

			var buf bytes.Buffer
			buf.WriteString(nick)
			buf.WriteByte(0)
			buf.WriteString(nick)
			buf.WriteByte(0)
			buf.WriteString(pass)
			payload := base64.StdEncoding.EncodeToString(buf.Bytes())
			c.WriteMessage(&irc.Message{
				Command: "AUTHENTICATE",
				Params:  []string{payload},
			})
		case irc.RPL_SASLSUCCESS:
			break loop
		case irc.ERR_NICKLOCKED, irc.ERR_SASLFAIL, irc.ERR_SASLTOOLONG,
			irc.ERR_SASLABORTED, irc.ERR_SASLALREADY, irc.RPL_SASLMECHS:
			return errors.New(strings.Join(msg.Params[1:], " "))
		}
	}

	if netid != "" {
		c.WriteMessage(&irc.Message{
			Command: "BOUNCER",
			Params:  []string{"BIND", netid},
		})
	}

	c.WriteMessage(&irc.Message{
		Command: "CAP",
		Params:  []string{"END"},
	})
	return nil
}

func (c *client) ReadMessage() (*message, error) {
@@ -143,6 +183,14 @@ func (c *client) ReadMessage() (*message, error) {
				c.caps.chatHistory = ok
			case "soju.im/bouncer-networks":
				c.caps.bouncerNetworks = ok
			case "sasl":
				if !ok {
					return nil, fmt.Errorf("server doesn't support SASL authentication")
				}
				c.WriteMessage(&irc.Message{
					Command: "AUTHENTICATE",
					Params:  []string{"PLAIN"},
				})
			}
		}
	case "BATCH":
diff --git a/main.go b/main.go
index c05e494..26e9e23 100644
--- a/main.go
+++ b/main.go
@@ -107,7 +107,9 @@ func main() {
	defer c.Close()

	c.Debug = debug
	c.Register(nick, pass)
	if err := c.Authenticate(nick, pass, ""); err != nil {
		log.Fatalf("Authentication failed: %v", err)
	}
	waitRegistered(c)

	if c.caps.bouncerNetworks {
@@ -122,9 +124,10 @@ func main() {
				log.Fatalf("Failed to connect to server: %v", err)
			}

			// TODO: use BOUNCER BIND instead
			c.Debug = debug
			c.Register(nick+"/"+network.name, pass)
			if err := c.Authenticate(nick, pass, network.id); err != nil {
				log.Fatalf("Authentication failed: %v", err)
			}
			waitRegistered(c)

			networkDir := filepath.Join(outputDir, escapeFilename(network.name))
-- 
2.34.2
chathistorysync/patches/.build.yml: SUCCESS in 30s

[Use BOUNCER BIND to bind to bouncer networks][0] from [Adnan Maolood][1]

[0]: https://lists.sr.ht/~emersion/public-inbox/patches/31190
[1]: mailto:me@adnano.co

✓ #737946 SUCCESS chathistorysync/patches/.build.yml https://builds.sr.ht/~emersion/job/737946