mirror of
https://github.com/gissleh/irc.git
synced 2026-09-29 00:05:34 +00:00
This commit is contained in:
@@ -2,9 +2,11 @@ package irc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
@@ -35,6 +37,7 @@ var supportedCaps = []string{
|
||||
"account-tag",
|
||||
"echo-message",
|
||||
"draft/languages",
|
||||
"sasl",
|
||||
}
|
||||
|
||||
// ErrNoConnection is returned if you try to do something requiring a connection,
|
||||
@@ -850,30 +853,33 @@ func (client *Client) handleEvent(event *Event) {
|
||||
// Nick rotation
|
||||
case "packet.431", "packet.432", "packet.433", "packet.436":
|
||||
{
|
||||
client.mutex.RLock()
|
||||
hasRegistered := client.nick != ""
|
||||
client.mutex.RUnlock()
|
||||
// Ignore if client is registered
|
||||
if client.Nick() != "" {
|
||||
break
|
||||
}
|
||||
// Ignore if in middle of SASL authentication
|
||||
if event.Verb() == "433" && client.Value("sasl.usingMethod") != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if !hasRegistered {
|
||||
nick := event.Args[1]
|
||||
nick := event.Args[1]
|
||||
|
||||
// "AltN" -> "AltN+1", ...
|
||||
prev := client.config.Nick
|
||||
sent := false
|
||||
for _, alt := range client.config.Alternatives {
|
||||
if nick == prev {
|
||||
_ = client.Sendf("NICK %s", alt)
|
||||
sent = true
|
||||
break
|
||||
}
|
||||
|
||||
prev = alt
|
||||
// "AltN" -> "AltN+1", ...
|
||||
prev := client.config.Nick
|
||||
sent := false
|
||||
for _, alt := range client.config.Alternatives {
|
||||
if nick == prev {
|
||||
_ = client.Sendf("NICK %s", alt)
|
||||
sent = true
|
||||
break
|
||||
}
|
||||
|
||||
if !sent {
|
||||
// "LastAlt" -> "Nick23962"
|
||||
_ = client.Sendf("NICK %s%05d", client.config.Nick, mathRand.Int31n(99999))
|
||||
}
|
||||
prev = alt
|
||||
}
|
||||
|
||||
if !sent {
|
||||
// "LastAlt" -> "Nick23962"
|
||||
_ = client.Sendf("NICK %s%05d", client.config.Nick, mathRand.Int31n(99999))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,6 +964,30 @@ func (client *Client) handleEvent(event *Event) {
|
||||
|
||||
// Special cases for supported tokens
|
||||
switch token {
|
||||
case "sasl":
|
||||
{
|
||||
if client.config.SASL == nil {
|
||||
break
|
||||
}
|
||||
|
||||
mechanisms := strings.Split(client.capData[token], ",")
|
||||
selectedMechanism := ""
|
||||
if len(mechanisms) == 0 || mechanisms[0] == "" {
|
||||
selectedMechanism = "PLAIN"
|
||||
}
|
||||
for _, mechanism := range mechanisms {
|
||||
if mechanism == "PLAIN" && selectedMechanism == "" {
|
||||
selectedMechanism = "PLAIN"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add better mechanisms
|
||||
if selectedMechanism != "" {
|
||||
_ = client.Sendf("AUTHENTICATE %s", selectedMechanism)
|
||||
client.SetValue("sasl.usingMethod", "PLAIN")
|
||||
}
|
||||
}
|
||||
|
||||
case "draft/languages":
|
||||
{
|
||||
if len(client.config.Languages) == 0 {
|
||||
@@ -1051,6 +1081,46 @@ func (client *Client) handleEvent(event *Event) {
|
||||
}
|
||||
}
|
||||
|
||||
// SASL
|
||||
case "packet.authenticate":
|
||||
{
|
||||
if event.Arg(0) != "+" {
|
||||
break
|
||||
}
|
||||
|
||||
method, ok := client.Value("sasl.usingMethod").(string)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
switch method {
|
||||
case "PLAIN":
|
||||
{
|
||||
parts := [][]byte{
|
||||
[]byte(client.config.SASL.AuthenticationIdentity),
|
||||
[]byte(client.config.SASL.AuthorizationIdentity),
|
||||
[]byte(client.config.SASL.Password),
|
||||
}
|
||||
plainString := base64.StdEncoding.EncodeToString(bytes.Join(parts, []byte{0x00}))
|
||||
|
||||
_ = client.Sendf("AUTHENTICATE %s", plainString)
|
||||
}
|
||||
}
|
||||
}
|
||||
case "packet.904": // Auth failed
|
||||
{
|
||||
// Cancel authentication.
|
||||
_ = client.Sendf("AUTHENTICATE *")
|
||||
client.SetValue("sasl.usingMethod", (interface{})(nil))
|
||||
}
|
||||
case "packet.903", "packet.906": // Auth ended
|
||||
{
|
||||
// A bit dirty, but it'll get the nick rotation started again.
|
||||
if client.Nick() == "" {
|
||||
_ = client.Sendf("NICK %s", client.config.Nick)
|
||||
}
|
||||
}
|
||||
|
||||
// User/host detection
|
||||
case "packet.352": // WHO reply
|
||||
{
|
||||
|
||||
@@ -36,6 +36,15 @@ type Config struct {
|
||||
|
||||
// Auto-join on invite (bad idea).
|
||||
AutoJoinInvites bool `json:"autoJoinInvites"`
|
||||
|
||||
// Use SASL authorization if supported.
|
||||
SASL *SASLConfig `json:"sasl"`
|
||||
}
|
||||
|
||||
type SASLConfig struct {
|
||||
AuthenticationIdentity string `json:"authenticationIdentity"`
|
||||
AuthorizationIdentity string `json:"authorizationIdentity"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// WithDefaults returns the config with the default values
|
||||
|
||||
Reference in New Issue
Block a user