Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1f58373

Browse files
committedJul 3, 2021
Add support for SASL EXTERNAL mechanism
1 parent 30a058a commit 1f58373

File tree

3 files changed

+111
-2
lines changed

3 files changed

+111
-2
lines changed
 

‎examples/simple-tor.go/simple-tor.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"github.com/thoj/go-ircevent"
5+
"crypto/tls"
6+
"log"
7+
"os"
8+
)
9+
10+
const addr = "libera75jm6of4wxpxt4aynol3xjmbtxgfyjpu34ss4d7r7q2v5zrpyd.onion:6697"
11+
12+
// This demos connecting to Libera.Chat over TOR using SASL EXTERNAL and a TLS
13+
// client cert. It assumes a TOR SOCKS service is running on localhost:9050
14+
// and requires an existing account with a fingerprint already registered. See
15+
// https://libera.chat/guides/connect#accessing-liberachat-via-tor for details.
16+
//
17+
// Pass the full path to your cert and key on the command line like so:
18+
// $ go run simple-tor.go my-nick my-cert.pem my-key.pem
19+
20+
func main() {
21+
os.Setenv("ALL_PROXY", "socks5h://localhost:9050")
22+
nick := os.Args[1]
23+
pemCert, err := os.ReadFile(os.Args[2])
24+
if err != nil {
25+
log.Fatal(err)
26+
}
27+
pemKey := pemCert
28+
if len(os.Args) == 4 {
29+
pemKey, err = os.ReadFile(os.Args[3])
30+
}
31+
if err != nil {
32+
log.Fatal(err)
33+
}
34+
clientCert, err := tls.X509KeyPair(pemCert, pemKey)
35+
if err != nil {
36+
log.Fatal(err)
37+
}
38+
ircnick1 := nick
39+
irccon := irc.IRC(ircnick1, nick)
40+
irccon.VerboseCallbackHandler = true
41+
irccon.UseSASL = true
42+
irccon.SASLMech = "EXTERNAL"
43+
irccon.Debug = true
44+
irccon.UseTLS = true
45+
irccon.TLSConfig = &tls.Config{
46+
InsecureSkipVerify: true,
47+
Certificates: []tls.Certificate{clientCert},
48+
}
49+
irccon.AddCallback("001", func(e *irc.Event) { })
50+
irccon.AddCallback("376", func(e *irc.Event) {
51+
log.Println("Quitting")
52+
irccon.Quit()
53+
})
54+
err = irccon.Connect(addr)
55+
if err != nil {
56+
log.Fatal(err)
57+
}
58+
irccon.Loop()
59+
}

‎irc_sasl.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ func (irc *Connection) setupSASLCallbacks(result chan<- *SASLResult) (callbacks
3131
}
3232
}
3333
if e.Arguments[1] == "ACK" && listContains(e.Arguments[2], "sasl") {
34-
if irc.SASLMech != "PLAIN" {
35-
result <- &SASLResult{true, errors.New("only PLAIN is supported")}
34+
if irc.SASLMech != "PLAIN" && irc.SASLMech != "EXTERNAL" {
35+
result <- &SASLResult{true, errors.New("only PLAIN and EXTERNAL supported")}
3636
}
3737
irc.SendRaw("AUTHENTICATE " + irc.SASLMech)
3838
}
@@ -41,6 +41,10 @@ func (irc *Connection) setupSASLCallbacks(result chan<- *SASLResult) (callbacks
4141
callbacks = append(callbacks, CallbackID{"CAP", id})
4242

4343
id = irc.AddCallback("AUTHENTICATE", func(e *Event) {
44+
if irc.SASLMech == "EXTERNAL" {
45+
irc.SendRaw("AUTHENTICATE +")
46+
return
47+
}
4448
str := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s\x00%s\x00%s", irc.SASLLogin, irc.SASLLogin, irc.SASLPassword)))
4549
irc.SendRaw("AUTHENTICATE " + str)
4650
})

‎irc_sasl_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,49 @@ func TestConnectionSASL(t *testing.T) {
4141
}
4242
irccon.Loop()
4343
}
44+
45+
46+
// 1. Export SASLKeyPem="-----BEGIN PRIVATE KEY-----..."
47+
// 2. Export SASLCertPem="-----BEGIN CERTIFICATE-----..."
48+
// 3. Mask these above in CI runner
49+
// 4. Registered fingerprint with IRC network
50+
func TestConnectionSASLExternal(t *testing.T) {
51+
SASLServer := "irc.freenode.net:7000"
52+
keyPem := os.Getenv("SASLKeyPem")
53+
certPem := os.Getenv("SASLCertPem")
54+
55+
if certPem == "" || keyPem == "" {
56+
t.Skip("Env vars SASLKeyPem SASLCertPem not present, skipping")
57+
}
58+
if testing.Short() {
59+
t.Skip("skipping test in short mode.")
60+
}
61+
cert, err := tls.X509KeyPair([]byte(certPem), []byte(keyPem))
62+
if err != nil {
63+
t.Fatalf("SASL EXTERNAL cert creation failed: %s", err)
64+
}
65+
66+
irccon := IRC("go-eventirc", "go-eventirc")
67+
irccon.VerboseCallbackHandler = true
68+
irccon.Debug = true
69+
irccon.UseTLS = true
70+
irccon.UseSASL = true
71+
irccon.SASLMech = "EXTERNAL"
72+
irccon.TLSConfig = &tls.Config{
73+
InsecureSkipVerify: true,
74+
Certificates: []tls.Certificate{cert},
75+
}
76+
irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") })
77+
78+
irccon.AddCallback("366", func(e *Event) {
79+
irccon.Privmsg("#go-eventirc", "Test Message SASL EXTERNAL\n")
80+
time.Sleep(2 * time.Second)
81+
irccon.Quit()
82+
})
83+
84+
err = irccon.Connect(SASLServer)
85+
if err != nil {
86+
t.Fatalf("SASL EXTERNAL failed: %s", err)
87+
}
88+
irccon.Loop()
89+
}

0 commit comments

Comments
 (0)
Please sign in to comment.