mirror of
https://github.com/gissleh/irc.git
synced 2026-10-19 03:32:54 +00:00
This commit is contained in:
@@ -2,9 +2,11 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -35,6 +37,7 @@ var supportedCaps = []string{
|
|||||||
"account-tag",
|
"account-tag",
|
||||||
"echo-message",
|
"echo-message",
|
||||||
"draft/languages",
|
"draft/languages",
|
||||||
|
"sasl",
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrNoConnection is returned if you try to do something requiring a connection,
|
// ErrNoConnection is returned if you try to do something requiring a connection,
|
||||||
@@ -850,11 +853,15 @@ func (client *Client) handleEvent(event *Event) {
|
|||||||
// Nick rotation
|
// Nick rotation
|
||||||
case "packet.431", "packet.432", "packet.433", "packet.436":
|
case "packet.431", "packet.432", "packet.433", "packet.436":
|
||||||
{
|
{
|
||||||
client.mutex.RLock()
|
// Ignore if client is registered
|
||||||
hasRegistered := client.nick != ""
|
if client.Nick() != "" {
|
||||||
client.mutex.RUnlock()
|
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", ...
|
// "AltN" -> "AltN+1", ...
|
||||||
@@ -875,7 +882,6 @@ func (client *Client) handleEvent(event *Event) {
|
|||||||
_ = client.Sendf("NICK %s%05d", client.config.Nick, mathRand.Int31n(99999))
|
_ = client.Sendf("NICK %s%05d", client.config.Nick, mathRand.Int31n(99999))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case "packet.nick":
|
case "packet.nick":
|
||||||
{
|
{
|
||||||
@@ -958,6 +964,30 @@ func (client *Client) handleEvent(event *Event) {
|
|||||||
|
|
||||||
// Special cases for supported tokens
|
// Special cases for supported tokens
|
||||||
switch token {
|
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":
|
case "draft/languages":
|
||||||
{
|
{
|
||||||
if len(client.config.Languages) == 0 {
|
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
|
// User/host detection
|
||||||
case "packet.352": // WHO reply
|
case "packet.352": // WHO reply
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,15 @@ type Config struct {
|
|||||||
|
|
||||||
// Auto-join on invite (bad idea).
|
// Auto-join on invite (bad idea).
|
||||||
AutoJoinInvites bool `json:"autoJoinInvites"`
|
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
|
// WithDefaults returns the config with the default values
|
||||||
|
|||||||
Reference in New Issue
Block a user